How do I marshal a lambda (Proc) in Ruby? - ruby

Joe Van Dyk asked the Ruby mailing list:
Hi,
In Ruby, I guess you can't marshal a lambda/proc object, right? Is
that possible in lisp or other languages?
What I was trying to do:
l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)
So, I'm sending BackgroundJob a lambda object, which contains the
context/code for what to do. But, guess that wasn't possible. I
ended up marshaling a normal ruby object that contained instructions
for what to do after the program ran.
Joe

You cannot marshal a Lambda or Proc. This is because both of them are considered closures, which means they close around the memory on which they were defined and can reference it. (In order to marshal them you'd have to Marshal all of the memory they could access at the time they were created.)
As Gaius pointed out though, you can use ruby2ruby to get a hold of the string of the program. That is, you can marshal the string that represents the ruby code and then reevaluate it later.

you could also just enter your code as a string:
code = %{
lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}
then execute it with eval
eval code
which will return a ruby lamda.
using the %{} format escapes a string, but only closes on an unmatched brace. i.e. you can nest braces like this %{ [] {} } and it's still enclosed.
most text syntax highlighters don't realize this is a string, so still display regular code highlighting.

If you're interested in getting a string version of Ruby code using Ruby2Ruby, you might like this thread.

Try ruby2ruby

I've found proc_to_ast to do the best job: https://github.com/joker1007/proc_to_ast.
Works for sure in ruby 2+, and I've created a PR for ruby 1.9.3+ compatibility(https://github.com/joker1007/proc_to_ast/pull/3)

Once upon a time, this was possible using ruby-internal gem (https://github.com/cout/ruby-internal), e.g.:
p = proc { 1 + 1 } #=> #<Proc>
s = Marshal.dump(p) #=> #<String>
u = Marshal.load(s) #=> #<UnboundProc>
p2 = u.bind(binding) #=> #<Proc>
p2.call() #=> 2
There are some caveats, but it has been many years and I cannot remember the details. As an example, I'm not sure what happens if a variable is a dynvar in the binding where it is dumped and a local in the binding where it is re-bound. Serializing an AST (on MRI) or bytecode (on YARV) is non-trivial.
The above code works on YARV (up to 1.9.3) and MRI (up to 1.8.7). There's no reason why it cannot be made to work on Ruby 2.x, with a small amount of effort.

If proc is defined into a file, U can get the file location of proc then serialize it, then after deserialize use the location to get back to the proc again
proc_location_array = proc.source_location
after deserialize:
file_name = proc_location_array[0]
line_number = proc_location_array[1]
proc_line_code = IO.readlines(file_name)[line_number - 1]
proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]
proc = eval("lambda #{proc_hash_string}")

Related

ruby - calling a method on a dynamically named object

I have an array of strings, that represent existing object names.
JoesDev = Dev.new
MarksDev = Dev.new
SamsDev = Dev.new
devices=['JoesDev', 'MarksDev', 'SamsDev' ]
i'd like to iterate over the devices array, while calling a method on the objects that each item in the array is named after.
i.e;
JoesDev.method_name
MarksDev.method_name
SamsDev.method_name
how can i do this? thx.
devices.each{|name| self.class.const_get(name).method_name}
You can use the const_get method from Module to have Ruby return the constant with the given name. In your case, it will return the Dev instance for whatever device name you give it.
Using .each to iterate the items, your code could look like
devices.each do |device_name|
device = self.class.const_get(device_name)
device.method_name
end
# Which can be shortened to
devices.each{ |dev| self.class.const_get(dev).method_name }
However, there are better ways to implement this type of thing. The most common way is using a Hash. In your example, the list of devices could look something like
devices = {
joe: Dev.new,
mark: Dev.new,
sam: Dev.new
}
Then, iterating over the devices is as simple as
devices.each do |dev|
dev.method_name
end
# Or
devices.each{ |dev| dev.method_name }
Extra: If you want to get a little fancy, you can use the block version of Hash::new to make adding new devices extremely simple.
# Create the hash
devices = Hash.new{ |hash, key| hash[key] = Dev.new }
# Add the devices
devices['joe']
devices['mark']
devices['sam']
This kind of hash works exactly the same as the one shown above, but will create a new entry if the given key cannot be found in the hash. A potential problem with this design, then, is that you can accidentally add new devices if you make a typo. For example
devices['jon'] # This would make a new Dev instance, which may be undesirable.
Well one way is surely to use eval, a method that allows you to execute arbitrary strings as if they were code.
So, in your example:
var_names.each{ |var_name| eval("#{var_name}.some_method") }
Needless to say, it is very dangerous to let unfiltered strings to be used as code, very bad things™ may happen!

Ruby: How to generate lines of code inside a program?

I am developing a parser in Ruby using the parslet library.
The language I am parsing has a lot of keywords that can be merged into a single parsing rule like this:
rule(:keyword) {
str('keyword1') |
str('keyword2') |
str('keyword2') ...
}
Is there a good way to generate this set of lines of code dynamically, by reading a text file with all the keywords?
This would help me keep my parser clean and small, making it easier to add new keywords without modifying the code.
The pseudo-code of what I want to embed inside the rule(:keyword) would be somethings like this:
File.read("keywords.txt").each { |k| write_line " str(\'#{k}\') "}
So far, the workaround I have found is to have a separate ruby program loading the parser code as:
keywords = ["keyword1", "keyword2","keyword3"]
subs = {:keyword_list => keywords .inject("") { |a,k| a << "str('#{k}') | \n"} }
eval( File.read("parser.rb") % subs)
where the parser code has the following lines:
rule(:keywords){
%{keyword_list}
}
Is there a more elegant way to achieve this?
You can try something like this:
rule(:keyword) {
File.readlines("keywords.txt").map { |k| str(k.chomp) }.inject(&:|)
}
In this case, you don't really need to "generate lines of code". As #Uri tried to explain in his answer, there's nothing special about the contents of that rule method; it's just plain Ruby code. Because of this, anything you can do in Ruby you can do inside that rule method as well, including read files, dynamically call methods, and call methods on objects.
Let me break down your existing code, so I can better explain how a dynamic solution to the same problem would work:
rule(:keyword) {
# Stuff here
}
This code right here calls a rule method and passes it :keyword and a block of code. At some point, parslet will call that block and check its return value. Parslet might choose to call the block using instance_exec, which can change the context the block is being executed in to make methods not available outside the block (like str, perhaps) available inside it.
str('keyword1')
Here, inside the context of the rule block, you are calling a method named str with the string "keyword1", and getting the result. Nothing special here, this is just a normal method call.
str('keyword1') | str('keyword2')
Here, the | operator is actually just a method being called on whatever str('keyword1') is returning. This code is equivalent to str('keyword1').send(:'|', str('keyword2')).
str('keyword1') |
str('keyword2') |
str('keyword2')
Same as before, except this time we're calling | on whatever str('keyword1').send(:'|', str('keyword2')) returned. The result of this method call is returned to the rule method when it calls the block.
So now that you know how all this works, you can perform exactly the same operations (calling str with each keyword, and using the | method to "add up" the results) dynamically, based on the contents of a file perhaps:
rule(:keyword) {
File.readlines("keywords.txt").map(&:chomp).map { |k| str(k) }.inject(:|)
}
Breakdown:
rule(:keyword) { # Call the rule method with the `:keyword` argument, and pass
# it this block of code.
File.readlines("keywords.txt"). # Get an array of strings containing all the
# keywords
map(&:chomp). # Remove surrounding whitespace from each keyword in the array,
# by calling `chomp` on them. (The strings returned by
# `File.readlines` include the newline character at the end of
# each string.)
map { |k| str(k) }. # Convert each keyword in the array into whatever is
# returned by calling `str` with that keyword.
inject(:|) # Reduce the returned objects to a single one using the `|`
# method on each object. (Equivalent to obj1 | obj2 | obj3...)
}
And that's it! See? No need to generate any lines of code, just do what the real code is doing, but do it dynamically!

What is my method returning here?

I have a question that I've already found the solution to (or perhaps it is just chance), but I'm hoping someone can explain why it works, and what Ruby is doing being the scenes here.
I'm doing something with fixed width output text and ANSI color codes. I don't want the escaped characters to count towards my length, so I wrote a little method for the String class to calculate the length excluding the color codes:
def length_minus_codes
color_codes = [ "\033[30m",
"\033[0m" ,
"\033[31m",
"\033[32m",
"\033[33m",
"\033[34m",
"\033[35m",
"\033[36m",
"\033[37m",
"\033[40m",
"\033[41m",
"\033[42m",
"\033[43m",
"\033[44m",
"\033[45m",
"\033[46m",
"\033[47m",
"\033[1m",
"\033[22m",
"\033[7m",
"\033[27m"]
#Create new variable to strip
stripped_self = self
#loop through color code array
for index in 0 ... color_codes.size
#strip color codes from string
stripped_self.gsub!(color_codes[index],"")
end
#return variance of self to stripped self to
#get length of string not including color codes
return self.length - (self.length - stripped_self.length)
end
end
I thought it was working fine, until I realized that after it was called, the string it was called on had the character codes stripped from it.
I tried a few things, before decided to change this:
stripped_self.gsub!(color_codes[index],"")
To this:
stripped_self = stripped_self.gsub(color_codes[index],"")
Now it is working fine.
What I don't understand is why? I understand the basic concept of in place methods (!) which I was using on the gsub, but it wasn't modifying self, but rather a variable that I set in the method, and second I only want to return the length of the string, not an actual string.
Can anyone explain what is happening here?
When you do
stripped_self = self
you are simply creating a new reference to the self string object, you are not creating a new string. So any in-place modifications (by gsub! in this case) will be reflected on the self object.
If you want to create a new object that is not a reference, you need to duplicate the object:
stripped_self = self.dup
Possibly a simpler solution here is just to use the non-bang version of gsub and save that to a variable. gsub! changes the receiver as bang methods often do, gsub will simply return a modified object safely without effecting the receiver.

How do I elegantly handle nil cases in my array assignment - Ruby?

So I am pushing some elements on my array like this:
upd_city_list << [ j.children[0].text.strip!.gsub(/\s+\W/, ''), j.children[1].text, j.children[1][:href] ]
The above is in an iterator (hence the use of j).
The issue is that from time to time, the j.children[0].text turns up as nil, and Ruby doesn't like that.
I could add a bunch of if statements before this assignment, but that seems a bit inelegant to me.
How do I handle nil cases in this situation in an elegant way?
One possible solution is, when there is a nil value, just push the string none onto the array....but what would that look like?
Thanks.
Edit1:
This is the error I am getting:
NoMethodError: private method ‘gsub’ called for nil:NilClass
The real problem is that strip! returns nil when there are no changes to the string. Your text method is returning a string, it is your strip! method is returning nil. I don't know why it does this. I dislike it, too.
This case of the problem will go away if you just change strip! to strip
In a more general sense, you might create an object to return the array for you. You don't want to go changing (what I assume is) Nokogiri, but you can wrap it in something to hide the train wrecks that result.
You should replace j.children[0].text.strip! with one of two things:
(j.children[0].text || 'none').strip
or
j.children[0].text.to_s.strip
These will, of course, have different effects when the text is nil. I think your ACTUAL problem is that strip! was returning nil, and that should have been obvious to you from the error message.
This might be the case for one to use null object programming pattern. Nil is not a good null object. Try reading here and here. Null object is the elegant way.
nil or a_string will be a_string
so what about (j.children[0].text or 'none')
If you're in rails, this is a great use for the try method.
Also seems that your strip and gsub are redundent. Please consider this implementation:
descriptive_name_1 = j.children[0].text.try(:strip)
descriptive_name_2 = j.children[1].text
descriptive_name_3 = j.children[1][:href]
updated_city_list << [ descriptive_name_1 , descriptive_name_2, descriptive_name_3 ]
w/o try
descriptive_name_1 = j.children[0].text.to_s.strip
descriptive_name_2 = j.children[1].text
descriptive_name_3 = j.children[1][:href]
updated_city_list << [ descriptive_name_1 , descriptive_name_2, descriptive_name_3 ]
If you're in the rails environment you could try try method: https://github.com/rails/rails/blob/82d41c969897cca28bb318f7caf301d520a2fbf3/activesupport/lib/active_support/core_ext/object/try.rb#L50

Rails String Interpolation in a string from a database

So here is my problem.
I want to retrieve a string stored in a model and at runtime change a part of it using a variable from the rails application. Here is an example:
I have a Message model, which I use to store several unique messages. So different users have the same message, but I want to be able to show their name in the middle of the message, e.g.,
"Hi #{user.name}, ...."
I tried to store exactly that in the database but it gets escaped before showing in the view or gets interpolated when storing in the database, via the rails console.
Thanks in advance.
I don't see a reason to define custom string helper functions. Ruby offers very nice formatting approaches, e.g.:
"Hello %s" % ['world']
or
"Hello %{subject}" % { subject: 'world' }
Both examples return "Hello world".
If you want
"Hi #{user.name}, ...."
in your database, use single quotes or escape the # with a backslash to keep Ruby from interpolating the #{} stuff right away:
s = 'Hi #{user.name}, ....'
s = "Hi \#{user.name}, ...."
Then, later when you want to do the interpolation you could, if you were daring or trusted yourself, use eval:
s = pull_the_string_from_the_database
msg = eval '"' + s + '"'
Note that you'll have to turn s into a double quoted string in order for the eval to work. This will work but it isn't the nicest approach and leaves you open to all sorts of strange and confusing errors; it should be okay as long as you (or other trusted people) are writing the strings.
I think you'd be better off with a simple micro-templating system, even something as simple as this:
def fill_in(template, data)
template.gsub(/\{\{(\w+)\}\}/) { data[$1.to_sym] }
end
#...
fill_in('Hi {{user_name}}, ....', :user_name => 'Pancakes')
You could use whatever delimiters you wanted of course, I went with {{...}} because I've been using Mustache.js and Handlebars.js lately. This naive implementation has issues (no in-template formatting options, no delimiter escaping, ...) but it might be enough. If your templates get more complicated then maybe String#% or ERB might work better.
one way I can think of doing this is to have templates stored for example:
"hi name"
then have a function in models that just replaces the template tags (name) with the passed arguments.
It can also be User who logged in.
Because this new function will be a part of model, you can use it like just another field of model from anywhere in rails, including the html.erb file.
Hope that helps, let me know if you need more description.
Adding another possible solution using Procs:
#String can be stored in the database
string = "->(user){ 'Hello ' + user.name}"
proc = eval(string)
proc.call(User.find(1)) #=> "Hello Bob"
gsub is very powerful in Ruby.
It takes a hash as a second argument so you can supply it with a whitelist of keys to replace like that:
template = <<~STR
Hello %{user_email}!
You have %{user_voices_count} votes!
Greetings from the system
STR
template.gsub(/%{.*?}/, {
"%{user_email}" => 'schmijos#example.com',
"%{user_voices_count}" => 5,
"%{release_distributable_total}" => 131,
"%{entitlement_value}" => 2,
})
Compared to ERB it's secure. And it doesn't complain about single % and unused or inexistent keys like string interpolation with %(sprintf) does.

Resources