Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Easier JS Syntax #396

Closed
wants to merge 20 commits into from
Closed

Easier JS Syntax #396

wants to merge 20 commits into from

Conversation

Largo
Copy link

@Largo Largo commented Feb 29, 2024

** Sorry, This is only a draft. Any help to improve this is welcome**

Todo:

  • Add Tests
  • Refactor the code
  • Extend == Operator to support comparisions with JS.eval for numbers

I'm using this in my projects: Ruby Koans on the Browser
Ruby.wasm Quickstart

Using method missing for allowing easier JS syntax. #228

  • Type conversion from JS::Object to regular Ruby Objects
  • == Comparison for nil and true
  • Make JSObjects enumerable to support each methods etc.
  • Implement respond_to and allow seeing the available methods in IRB (only one level down so far Object1.method1.method2 does not work)

image

Shopping List Example code:

JS.global.document.getElementById("spinner").style.display = "none"
        require "json"
        @document = JS.global.document
        @list = @document.getElementById("shopping-list")
        @input = @document.getElementById("new-item")
        @button = @document.getElementById("add-item")
        @storage = JS.global.localStorage

        def getItems()
          @storage.getItem("shoppingItems")
        end
        def updateStorage()
          items = []
            @document.getElementById("shopping-list").querySelectorAll("li").to_a.each do |item|
            label = item.querySelector("label").innerText
            isChecked = item.querySelector("[type=checkbox]").checked
            items.push({label:, isChecked:})
          end
          @storage.setItem("shoppingItems", JSON.generate(items))
        end

        def add_item(name, checked=false, shouldUpdateStorage=true)
          return if name.nil? || name&.strip&.empty?
          li = @document.createElement("li")
          checkbox = @document.createElement("input")
          checkbox.type = "checkbox"
          checkbox.checked = checked
          label = @document.createElement("label")
          label.innerText = name
          label.addEventListener("click") { |e| enable_editing(e.target) }
          li.appendChild(checkbox)
          li.appendChild(label)
          input = @document.createElement("input")
          input.type = "text"
          input.className = "edit-input"
          input.addEventListener("blur") { |e| update_item(e.target) }
          input.addEventListener("keypress") do |e|
            e.target.blur if e.key == "Enter"
          end
          li.appendChild(input)
          @list.appendChild(li)
          @input.value = ""
          updateStorage if shouldUpdateStorage
        end

        def enable_editing(label)
          input = label.nextSibling
          input.value = label.innerText
          label.style.display = "none"
          input.style.display = "block"
          input.focus
        end

        def update_item(input)
          label = input.previousSibling
          label.innerText = input.value.strip.empty? ? label.innerText : input.value
          label.style.display = "block"
          input.style.display = "none"
          updateStorage()
        end

        @button.addEventListener("click") { add_item(@input.value) }
        @input.addEventListener("keypress") do |e|
          add_item(@input.value) if e.key == "Enter"
        end
        @list.addEventListener("change") do |e|
        updateStorage
        end
        

        JSON.parse(getItems || "[]")&.to_a.each do |item|
          p item
          add_item(item["label"], item["isChecked"], false)
        end

@Largo Largo marked this pull request as draft February 29, 2024 09:24
Copy link
Member

@kateinoigakukun kateinoigakukun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't have enough time to review all changes, but as a general feedback, would you mind splitting changes into smaller PRs and writing tests to cover new functionalities? It helps me a lot to review and I think it will give you some insights on edge cases.


# Try to convert JS Objects into Ruby Objects
# Todo: make a list of Types that need to remain JS::Objects (array methods?)
def to_rb
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you noticed, there is no obvious mapping from JavaScript objects to Ruby objects. Also for most use cases, what we really need is conversion to a specific type like to_i and to_s. So TBH I'm not sure if it's worth introducing this kind of generic conversion method.

Comment on lines +207 to +209
# Support self == true instead of self == JS:True
alias_method :orig_eq, :==
def ==(other)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about comparing self with other.to_js?


def each(&block)
if block_given?
self.isJSArray ? self.to_a.each(&block) : Array.new(__props).each(&block)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I feel iterating on object properties is a little bit tricky. Do you have any use case for this behavior? I prefer simply delegating to self.to_a.each

@Largo Largo deleted the branch ruby:main April 15, 2024 08:21
@Largo Largo closed this Apr 15, 2024
@Largo Largo deleted the main branch April 15, 2024 08:21
@Largo
Copy link
Author

Largo commented May 3, 2024

I accidentaly closed this. I'm working on a new version that will be easier to review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants