On Tue, Apr 24, 2012 at 13:18, Karol Bucek <karol.bu
...@gmail.com> wrote:
> Hey, I'd like to propose a way of how JavaScript functions expose their
> context (this) into their Ruby implementations.
> This is mostly relevant for Procs/lambdas as they in Ruby are bind to the
> defining context but it's fairly useful to be able to mirror JS functions
> with those as close as possible.
> Most functions look like these:
> ```
> function hello(name) { return 'Hello ' + name; }
> ```
> A similar Ruby version would than look like:
> ```
> context['hello'] = lambda { |name| "Hello #{name}" }
> ```
> This is fine and predictable but than suppose you need to get the context
> passed:
> ```
> function hello(greet) { return greet.toString() + this; }
> hello.call(42, 'Hello');
> ```
> Now for Ruby this would be possible but only if the user can guarantee
> there's no "surrounding" instance state accessed by the closure e.g. :
> ```
> some = 'some'proc = lambda { |local| "#{self}: #{some} #{local}" }puts proc.call('another') # main: some anotherputs 42.instance_exec('other', &proc) # 42: some another
> ```
> with this case the Ruby exposed hello would look similar to the JavaScript
> version:
> ```
> context['hello'] = lambda { |greet| "#{greet.to_s} #{self}" }
> ```
> A simpler approach that would not require "instance state caution" would
> be to pass in this as a first argument :
> ```
> context['hello'] = lambda { |this, greet| "#{greet} #{this}" } # self
> unmodified
> ```
> but that this also comes for a price - now your lambdas do not map 1:1
> with JS arguments and this is especially confusing since most of the time
> you do not care about the this with ("anonymous") functions ...
> I'd like to propose a "choice" for users, since their in control of the
> context creation (or the libraries they use are), they should be able to
> decide which behavior they need the option name should be discussed here's
> a draft :
> :lambda_this_argument => :none
> :lambda_this_argument => :pass
> :lambda_this_argument => :bind
> usage sample: `V8::Context.new(:lambda_this_argument => :pass) do ...`
> I would expect :none ("no magic") to be the default, but than of course
> there's therubyracer 0.10 that already does :pass by default ...
> p.s. Some bits of this discussion originally started here:
> https://github.com/metaskills/less-rails/pull/34