Feature #8643
closedAdd Binding.from_hash
Description
Binding.from_hash
would work like:
class Binding
def self.from_hash(hash)
OpenStruct.new(hash){ binding }
end
end
It would simplify things like:
ERB.new(IO.read 'template.erb').result Binding.from_hash(template_local: 'example')
Or if you need to eval
some code in another process (JRuby, for instance) and need to pass some arguments to the eval
code in a hash form.
I didn't want to pollute Hash
by adding Hash#to_binding
. I believe Binding.from_hash
is more appropriate.
Files
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
Whoops. I can't update the description. The implementation should be:
OpenStruct.new(hash).instance_eval { binding }
Updated by Anonymous over 11 years ago
Personally I think hash keys should be local variables in the binding, not method calls against self.
It's hard to express this in Ruby, but this can easily be done from the C side.
Updated by Anonymous over 11 years ago
PS: I'm neutral towards this feature. I've got no strong feelings that it should or shouldn't be part of Ruby.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
I don't mind on it being a local var in the binding since it should work either way, just an implementation detail I'd say... Maybe other Ruby implementations might prefer to use them as methods?
Updated by ko1 (Koichi Sasada) over 11 years ago
- Assignee set to ko1 (Koichi Sasada)
What do you think about [Feature #8761]?
Usage:
def get_empty_binding
binding
end
...
b = get_empty_binding
hash.each{|k, v|
b.local_variable_set(k, v)
}
# use b
I think that Binding#local_variable_set()
can be extended to accept one hash parameter (pairs of local variable name and value).
b = get_empty_binding
b.local_variable_set(hash)
b.local_variable_set(a: 1, b: 2)
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
I don't quite understand how that would help me, Koichi.
How could I use #8761 to get the same result as the example in the description?
ERB.new(IO.read 'template.erb').result Binding.from_hash(template_local: 'example')
My current alternative is:
ERB.new(IO.read 'template.erb').result OpenStruct.new(template_local: 'example'){ binding }
How would #8761 make it easier for me?
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
In other words, I want an easier way to convert a hash to a binding. I first thought about Hash#to_binding but it didn't feel right to me...
Updated by ko1 (Koichi Sasada) over 11 years ago
(2013/08/09 22:10), rosenfeld (Rodrigo Rosenfeld Rosas) wrote:
In other words, I want an easier way to convert a hash to a binding. I first thought about
Hash#to_binding
but it didn't feel right to me...
Ok. Maybe I misunderstood your proposal.
What is conversion from Hash
to Binding
?
I think it is Binding
has a local variables which specified pairs in Hash.
hash = {a: 1, b: 2}
b = Binding.to_hash(hash)
eval("p [a, b]", b) #=> [1, 2]
Could you explain what do you want?
--
// SASADA Koichi at atdot dot net
Updated by nobu (Nobuyoshi Nakada) over 11 years ago
(13/08/09 23:34), SASADA Koichi wrote:
What is conversion from
Hash
toBinding
?
I think it is Binding has a local variables which specified pairs inHash
.hash = {a: 1, b: 2} b = Binding.to_hash(hash)
Binding.from_hash
?
Updated by ko1 (Koichi Sasada) over 11 years ago
nobu (Nobuyoshi Nakada) wrote:
Binding.from_hash
?
Yes.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
Koichi-san, that's correct:
eval 'p a, b', Binding.from_hash(a: 1, b: 2) #=> 1, 2
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
I didn't notice I replied only to Koichi Sasada when replying to the ruby-core list. Is it possible to set it up so that the reply-to field is set to ruby-core?
Here is some discussion from us from those e-mails so that everyone could have access to it:
(2013/08/10 20:47), Rodrigo Rosenfeld Rosas wrote:
I'm not sure how else to explain it
The only API example I know that requires a binding is the ERB one
It's designed to be used this way:
a = 1
b = 2
erb.result binding # both a and b are available inside the template as
well as other methods and variables, like erb
Koichi wrote:Please try:
require 'erb' bind = binding bind.local_variable_set(:a, 1) bind.local_variable_set(:b, 2) puts ERB.new("<%= a %> and <%= b %>").result(bind) #=> 1 and 2
That works, but it is too much trouble for a simple requirements and
besides that more methods and variables may leak when using the current
binding.
That's why people will often use the "OpenStruct.new(hash){binding}
"
trick, since it's much shorter, but still a hack in my opinion.
This is often used in automation tools like Chef or Puppet where the
recipe settings (stored as a hash, usually) should be available for some
templates.
Suppose you have the NewRelic settings under settings[:new_relic]
hash
(eg.: { application_name: 'My App', enable_rum: true }
)
In such cases, when generating the newrelic.yml from a newrelic.yml.erb
template, those tools would process it as:
File.write 'newrelic/location/newrelic.yml', ERB.new(File.read 'path/to/newrelic.yml.erb').result OpenStruct.new(settings[:new_relic]){binding}
That's why I've created two tickets based on this common requirement. On
this specific one I'm suggesting a Binding.from_hash(hash)
to make it
easier to get a binding from a hash for usage in such API's. The other
one suggested ERB to accept also a hash, instead of a binding for #result
.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
Koichi then replied with:
I'm not sure what methods and variables are leaks.
For example, only "make_binding" mathod is leaked.
def make_binding(hash)
__b = binding
hash.each{|k, v|
__b.local_variable_set(k, v)
}
__b
end
created_binding = make_binding(a: 1, b: 2)
...
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
For that tiny script, this is true, Koichi, but usually we get a binding from some class, so all methods would be available as well as other intermediary local variables in the method calling erb#results
.
Like this:
class A
def a
1
end
def b
eval 'p a', binding
end
end
A.new.b # a has leaked
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 10 years ago
- File feature-8643.pdf feature-8643.pdf added
Add slide for proposal
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
Rodrigo Rosenfeld Rosas wrote:
The other one suggested ERB to accept also a hash, instead of a binding for
#result
.
It feels better to me.
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
- Description updated (diff)
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 8 years ago
Nobuyoshi Nakada wrote:
Rodrigo Rosenfeld Rosas wrote:
The other one suggested ERB to accept also a hash, instead of a binding for
#result
.It feels better to me.
Either one is fine to me as long as I can easily pass locals to ERB from a hash using a proper API :) Since this is the only use case I have in mind for Binding.from_hash
I agree with you that passing a hash to ERB constructor feels better.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 8 years ago
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
- Related to deleted (Feature #8430: Rational number literal)
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
- Related to Feature #8631: Add a new method to ERB to allow assigning the local variables from a hash added
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
Ticket links changed.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 8 years ago
Thanks!
Updated by ko1 (Koichi Sasada) almost 8 years ago
- Status changed from Open to Feedback
Can I close this issue?
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) almost 8 years ago
Updated by k0kubun (Takashi Kokubun) over 7 years ago
- Status changed from Feedback to Rejected
Since [Feature #8631] is accepted, closing this ticket.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 7 years ago
Yes, it makes sense. Thanks a lot! :)
Updated by hsbt (Hiroshi SHIBATA) almost 3 years ago
- Project changed from 14 to Ruby master