Git Product home page Git Product logo

Comments (11)

k33g avatar k33g commented on May 18, 2024

Hi,

can you please give some samples about using jquery or dom (like document.querySelectorAll), how to pass parameters to js commands ?

it's very interesting to be able coding with ruby in navigator, thanks for this

sorry about my english (i'm french)

from opal.

adambeynon avatar adambeynon commented on May 18, 2024

Well, using your given example Im currently trying to solve two issues: accessing 'global' js objects/variables (e.g. document), and calling native functions on objects (e.g. .querySelectorAll).

Accessing global js objects

The opal compiler has no way to know about global objects at compile time, i.e. it cannot look through your code and determine that document is actually the global document variable. Rubys syntax says that if a variable is not defined in the current scope, then it is intact a method call (called on the receiver). Unless every identifier is compiled to check for this, we cannot know how to treat it.

One solution I'm looking at is to override the use of global variables to compile down to basic javascript variable names. For example, the following ruby code:

foo = $document;

Would compile into something like:

var foo = document;

The opal compiler will determine that global var access is just accessing global javascript variables. Obviously special ruby globals ($$, $:, etc) will compile into a wrapper to their respective ruby variables. Similarly, global assignment could (should?) generate a global javascript variable.

If we wanted to be clever, we could compile these globals to check for a variable existence first and return nil if the given global var doesn't exist - so our example above could become:

var foo = (typeof document != undefined ? document : nil);

This is the best way I can see for easy access to js variables while keeping (mostly) ruby semantics.

Calling native functions

Once we have a reference to these global variables, accessing their functions is the tricky part. A feature (or pain) of js is that you can access functions, or other properties, of an object by omitting call parens (unlike ruby which calls a method anyway).

To keep things in opal fast, strings, numbers and arrays point to their native javascript equivalents. This has a side effect that every ruby array, string and number have these js properties already attached. The opal compiler therefore appends m$ to every method name so that [1, 2, 3].length compiles into [1, 2, 3].m$length() which avoids naming clashes as much as possible.

This also means that accessing a function, like querySelectorAll is not so easy, as calling that method on our document variable will compile into document.m$querySelectorAll(), which is why I proposed the :: syntax for native function calls.

The alternative

The alternative to these two 'solutions' is to make use of the current back tick syntax that can hold raw javascript, and is just output as given. For example, to use your given method, you could do:

elements = `document.querySelectorAll('div')`

# pass elements somewhere else
do_something_with_elements elements

# raises an error as elements does not have any ruby methods..
elements.try_some_method()

As nice as being able to directly call js methods would be, loosing specific ruby features that make ruby great would remove the benefit of being able to use ruby in the browser. I hope this clears up the current method of accessing js objects and what might make it into opal next.

from opal.

k33g avatar k33g commented on May 18, 2024

wahooo! thanks a lot, i'm going to play with it

from opal.

k33g avatar k33g commented on May 18, 2024

OK, i've understood

 def change(txt)
    `document.querySelector('h1').innerHTML = txt;`
end

from opal.

al6x avatar al6x commented on May 18, 2024

Nice project, is it supposed to be compatible with Node.js?

About access to JS, maybe it's possible to use something like this?

[1, 2, 3, 4].native.length
[1, 2, 3, 4].js.length

from opal.

adambeynon avatar adambeynon commented on May 18, 2024

It does work with node.js, but not in the master branch. I will be pushing node.js support in a day or so once I tidy up the file system methods.

I do like the approach using native, or some other special keyword - there is temporary code in the propery_access branch for accessing global js variables using something similar, using a special opal keyword:

opal.document   # => document
opal.window       # => window

I'll keep you updated here on the node.js updates.

from opal.

meh avatar meh commented on May 18, 2024

Why not using Ruby's global syntax to access globals?

$document and $window sounds better than opal.document and opal.window to me.

Didn't give a look at the property_access branch but I would go with defining if something is native or not in the class, with something on the lines of native :length, :size, :whatever and then check during compile if it's a native or a method call. Also adding Object#native, like @alexeyPetrushin suggested, would be cool.

from opal.

adambeynon avatar adambeynon commented on May 18, 2024

Yeah, the global syntax seems the better way. I think it should be used just for accessing globals - not writing, i.e. when setting a ruby global it shouldnt really set a global in js.

As for the property access, well, compile time detection wouldnt be all that easy. The compiler will not have access to some prototypes to check, for instance it won't know which jquery properties are simple properties, like length and selector, or which are actual functions. I guess you could have a couple of class methods such as:

class JQuery
    native_proptery :length, :selector

    native_function :next, :prev
end

... or something similar.

from opal.

meh avatar meh commented on May 18, 2024

Agree with the global setter being Ruby only.

I'd sincerely go with the super syntax to discern properties from functions, as in, always need parenthesis to call a native function.

from opal.

adambeynon avatar adambeynon commented on May 18, 2024

Im not sure I follow.. how would the compiler determine that a method call on a object is trying to access native properties/functions compared to a normal ruby method call? The dynamism of ruby means theres no guaranteed way to know the type of the receiver and therefore what its native properties are.

from opal.

meh avatar meh commented on May 18, 2024

Well, you coul keep a native thing table somewhere, but yeah, you're probably right, easier to go with native_property and native_function :)

from opal.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.