Why pass dot (.) separated string to "p"? - ruby

I'm working on some ERB templates that are not my own, and I see the developer has used statements like this a lot:
<%= p("object.property.foo") %>
Where object is an OpenStruct. This method call results in the value of object.property.foo being printed (as in JavaScript, or most languages I know). Which is awesome because it is much more simple than writing:
<%= object["property"]["foo"] %>
My questions are:
Why am I able to access properties with "." notation?
Why do I pass a string to p and not the object itself?
Why is p preferable in this case? (I know p vs. puts, but why use p here?)

<%= %> tells the ERB parser to evaluate the content as a ruby expression, and to include the return value in the resulting HTML text.
p( ) is likely to be a view helper function that creates some HTML tags. This is not obvious from the code fragment. Apparently it evaluates the string argument, again as another ruby expression. p is not a standard rails or ruby method.
object is according to the questioner an OpenStruct. OpenStruct is a data structure that combines the behaviour of a Hash with the syntax of class methods. It is documented here: http://ruby-doc.org/stdlib-2.1.0/libdoc/ostruct/rdoc/OpenStruct.html
object.property asks OpenStruct to apply property on object. OpenStruct replies with a stored value, something like #value[property], where #value would be a Hash. You do not need square bracket syntax, because OpenStruct provides dynamic access methods. The '.' is the ruby operator to apply a method to an object. The internal implementation of OpenStruct's data storage does not have be be a Hash at all. According to the questioner, the return value is another instance of OpenStruct.
object.property.foo calls method foo on the instance of OpenStruct that was returned from object.property. Now we receive the value of a nested OpenStruct object structure.

Seems to me that the developer may have aliased the eval statement with p somewhere earlier in the code.
require 'ostruct'
o = OpenStruct.new(key: 5)
o.key # returns 5
alias p eval
p("o.key") # returns 5
eval is simply a function that executes any string passed into it as ruby code.
Regarding your question
Why is p preferable in this case? (I know p vs. puts, but why use p here?)
I don't believe you are using the classic p function here. By default that p does not "eval" strings passed into it. The p function must have been overwritten with the eval function. Check the code base for something like alias p eval or alias_method :p, :eval

Related

Mutating list of instantiated objects in Rails

I'm attempting to clean up my view by moving Rails' sanitizer method to a helper, but it's not producing the desired result. So below is what my index action looks like. I know it's ugly and not very OOP, but I simplified it down so I could follow what was happening when debugging.
I'm attempting to loop through all the sources' attributes, running the sanitizer on any attribute that is a non-empty string, replacing original strings with the sanitized strings (transform_values!), and writing over the original #sources (map!).
I tried storing them in different variables than #sources and using .each instead of .map! but the sanitized values don't make it through.
def index
#sources = Source.all
#sources.map! { |source|
source.attributes.transform_values! { |attr|
attr.blank? || !attr.is_a?(String) ? attr
: ActionController::Base.helpers.sanitize(attr) } }
end
However, after examining my list of sources in the view, it's removing the source instances and instead returning a nondescript array of hashes. I can loop through these, but I can't call specific attributes like source.author which is not great.
Here's some images for reference. The first one is what it should look like and second is what I'm currently getting
Unsanitized sources
Sanitized sources
map! replaces each item in the array with the result of the block. This is not what you intend to do, because you just want to mutate the items, not replace them with something else. Use a plain each instead of map! would do the trick.
On another side, sanitization is actually a responsibility of the view (that’s why it’s defined in a helper). If you need to sanitize often with the same argument, define your own helper:
class ApplicationHelper
def sany(str)
sanitize(str, %w[...])
end
end
<%= sany(source.some_attr) %>
You could also set the default sanitization options following the documentation:
# In config/application.rb
config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
config.action_view.sanitized_allowed_attributes = ['href', 'title']

ruby, two ways how to pass params to proc

I looked through this code and found author passes params to block using []. I tryed it myself
my_proc = proc { |x| x + 1 }
a = 0
my_proc[a] # => 1
my_proc.call(a) # => 1
What is the difference between this two calls? Is this a syntax sugar?
Both ways are exactly the same and are aliases to each other. Thus, both variants call the same method which is not determined by any special syntax. It is basically defined as:
class Proc
def call(*args)
#...
end
alias [] call
end
You might be interested to note that there is even a third way:
my_proc.(a)
This is actually syntactic sugar (i.e. is an extension of the syntax of the Ruby language language). All objects accepting #call can be "called" that way and Ruby ensures to invoke the call method.
They are functionally identical. You can use whichever style you prefer.

How can I make a custom Ruby type behave like a string?

If I have a custom Ruby class representing some string type, as in
class MyString
end
Which functions should I implement in order to make the following use cases possible:
Passing a Ruby string whenever a MyString is expected
Passing a MyString whenever a Ruby string is expected
Comparing a Ruby string with a MyString value (it shouldn't matter whether I use s == t or t == s).
I saw various interesting functions like to_s, cmp, == and eq already, but it's not clear to me when each of them is called.
My concrete use case is that I'm writing a Ruby extension using the C API which exposes functions taking (and returning) values of a custom string type (QString, to be precise) which my extension also registers. However, I'd like to make those custom strings behave as intuitive as possible. Unfortunately I can't just return Ruby strings from my C code since it should be possible to call Qt methods on the strings.
There are at least three approaches:
class MyString < String; ...; end
Define #to_s
Define #to_str
Doing both #2 and #3 will make the object act very much like a real String even if it isn't a subclass.
#to_s is an explicit converter, meaning it must appear in Ruby code to work.
#to_str is an implicit converter, meaning the Ruby interpreter will attempt to call it when it wants a String but is given something else.
Update:
Here is an example of some fun you can have with to_str:
begin
open 1, 'r'
rescue TypeError => e
p e
end
class Fixnum
def to_str; to_s; end
end
open 1, 'r'
When run, the first open fails with TypeError but the second proceeds to looking for 1.
#<TypeError: can't convert Fixnum into String>
fun.rb:9:in `initialize': No such file or directory - 1 (Errno::ENOENT)
from fun.rb:9:in `open'
Although it's tempting to sub-class String to give it a new initialize method that will import these QString-type strings, you may just want to tack on an extension to String that helps with the conversion so you don't have to re-implement a version of String itself.
For instance, with two methods you could pretty much have this done:
class String
def self.from_qstring(qstring)
new(...)
end
def to_qstring
# ...
end
end
Having multiple storage types for String is not going to be a problem until you start comparing them, but given that Ruby's String is quite robust, writing a work-alike is difficult.
It's not generally a good idea to subclass classes that were built by someone else in Ruby, because too many things can go wrong. (You might, for example, override an internal method without knowing it.)
1) define Mystring.to_s to get automatic conversion from a Mystring to a String.
2) Not sure what you mean by this. If you want a String method that returns a Mystring, you will have to monkey-patch String:
Class String
def to_mystring
return Mystring.new(self)
end
end
3) to get t == s (assuming s is an instance of String and t an instance of Mystring) define <=>. To get s == t you will have to monkey patch String again, though.
Since I was looking for something similar, but none of the other answers worked for me, I'll post what did work for me.
Found in this blog post which discourage the use of inheriting String and instead use simple delegator.
Inheriting from SimpleDelegator create an object which delegate everything to a string of your choice but on which you add behavior as you see fit.
class ChunkyBacon < SimpleDelegator
def initialize(content)
#content = content
super #content
end
def chunky_bacon?
#content == 'chunky_bacon'
end
end
test = ChunkyBacon.new('choco pizza') # => 'choco pizza'
test.chunky_bacon? # => false

How to intercept the call to constructor of class Hash?

I want to execute a function when a constructor of class Hash is called or when a Hash object is initialized. I have implemented my objective using
class Hash
def initialize
p "Constructor call"
end
end
The code above works fine when a Hash object is initialized as follows:
a = Hash.new(:a1 => "Hi")
However, when I use the following code:
a = {:a1 => "Hi"}
Then, it fails or the constructor is not called. So, how to intercept the call made in the second code snippet?
Thanks in advance.
I'm afraid you can't in MRI, but could probably manage something in Rubinius / JRuby.
Unfortunately, just like in almost every other language, you cannot override literals in Ruby. You'll have to use one of the few languages that allow this, like Ioke:
cell(:{}) = method(+x, "Literal {} called with #{x inspect}" println)
{ :a1 => "Hi" }
;; Literal {} called with [:a1 => "Hi"]
(In fact, Ioke is the only language I can think of right now which allows literal overloading / overriding. I suppose Ioke's cousin Seph will support it, and a couple of years of ago there was some discussion about allowing it in Newspeak, but that's about it.)

translating blocks and statements for a DSL

I want to write a simple Ruby DSL to translate some statements and expressions into another language. A basic example would be:
some_function {
t + 2
}
Here, t is not a ruby variable and thus the block can't (and must not!) be evaluated by Ruby. So my best bet would be to use the parsing output (or AST) to do the translation myself. To do so, I can use ParseTree and ruby2ruby. However, I have other constructs that I would like to use, for example:
1.upto(10) {|x|
some_function {
t + x
}
}
Here, I have a local variable and I need to get its value in order to do my translation. However, in the function that does the block evaluation, I don't have access to the local variables of the calling block. If it were a global variable ($x), I could check if its name exists in the global_variables array and in the worst case use eval, but how could I do so for a local variable, if possible at all?
Update:
Just to clear up things. Like I said originally, I'm using ruby2ruby (and hence ParseTree) to get the AST (using to_sexp) corresponding to the block. But when using a local variable inside my block, I encounter the following:
[:dvar, :x]
And thus, I would need to get the value of a variable from its name as a string/symbol. And I can't use method_missing or instance_eval, because I want to translate the whole expression to another language or syntax (like a RPN).
Another solution not based on ParseTree would be welcome nonetheless, since it apparently is not fully supported with Ruby 1.9.
To get the variable values, use the proc's binding:
def some_function(&block)
b = block.binding
p [b.eval("t"), b.eval("x")]
end
t = 1
1.upto(10) {|x|
some_function {
t + x
}
}
Here, t is not a ruby variable and
thus the block can't (and must not!)
be evaluated by Ruby.
Any reason for the "not evaluated" restriction? It seems like method_missing would elegantly handle evaluating the "missing" t variable, but Ruby would automatically dereference the x variable.
You can use instance_eval against an object with t.
class Context
attr_accessor :t
def initialize(_t)
#t = _t
end
end
def some_function(&block)
puts Context.new(1).instance_eval(&block)
end
1.upto(10) {|x|
some_function {
t + x
}
}

Resources