Access Thor Option Hash - ruby

I want to merge a value into a Thor option hash.
If I just use merge I get an error, HashWithIndifferentAccess
I have read the documentation but I have difficulties to understand how to get it to work. I guess I hope this question will help me to both find an answer on the question how to merge a value into this kind of hash and understand how to read documentation.
p options.inspect
#=> "{\"ruby\"=>\"/Users/work/.rbenv/versions/1.9.2-p290/bin/ruby\"}"
p options.merge!(:a => true)
#=> hash_with_indifferent_access.rb:26:in `[]=': can't modify frozen hash (RuntimeError)

The hash is frozen:
"Prevents further modifications to obj. A RuntimeError will be raised
if modification is attempted. There is no way to unfreeze a frozen
object."
You can copy options to a new hash (will be unfrozen) and modifying that instead.
new_options = options.dup
options = new_options
options.merge!(:a => "this will work now")
Or if you want it to be even briefer:
options=options.dup
options.merge!(:a => "this will work now")
The Thor library returns a frozen hash by default, so another option would be to modify the library to return unfrozen hashes, but I think the first solution is good enough.
Below is a link to the source code for Thor's parse function, you'll notice it freezes the "assigns" return hash prior to actually returning it (go to the bottom of the page, and under (Object) parse(args), click 'View Source'. The freezing is on line 83 of the source snippet.)
http://rubydoc.info/github/wycats/thor/master/Thor/Options

Related

Ruby Sha256 hash continuation

I am interested in taking an existing hash and resuming the SHA256 encryption from that point. It seems doable in C++:
This is what I have tried:
irb(main):007:0> sha2 = Digest::SHA2.new => #<Digest::SHA2:256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855>
irb(main):008:0> sha2 << "string1"
=> #<Digest::SHA2:256 93fedde43203e0a76172135221b8636313635d7afff96a490ae9066330505d47>
irb(main):009:0> sha2 << "string2"
=> #<Digest::SHA2:256 bac09aa72e632e76c36e6c1c4e502b73c3da7fca68c475273dc5517815587cc4>
irb(main):010:0>
The above code updates the SHA2 digest object, in session. I want to start a new session...lets call it newshaw2 by assigning the same original hash as created when I passed String1 to sha2, as above.
I want to "make" newshaw2 as the object 93fedde43203e0a76172135221b8636313635d7afff96a490ae9066330505d47.
Setting it equal: newshaw2 = '93fedde43203e0a76172135221b8636313635d7afff96a490ae9066330505d47' just makes this a string object, not a digest.
Once, I have successfully assigned newsha2 with the hash then I would update with string2 to resume the hashing process.
It sounds like you want to be able to create a new Digest::SHA2 object and set its initial value to an existing hash without having to recalculate that hash.
For example, if you use Digest::SHA2 to calculate the hash for a 10 GB file, then is there any way to make a new Digest::SHA2 with that hash value but without having to rehash all 10 GB?
The answer is no, Digest does not have this capability. You can confirm that in one of a few ways. First, look at the public methods available on the object to see that there are no options to do this:
Digest::SHA256.new.public_methods - Object.public_methods
=> [:update, :digest_length, :block_length, :<<, :reset, :digest, :file, :base64digest, :base64digest!, :hexdigest!, :length, :digest!, :size, :hexdigest]
Then take a look at the source for initialize in Digest::SHA2 and you'll see there's no argument to set the initial state when calling new.
There may be something I missed because the source code for Digest is a little hard to follow because Digest is a mix of Ruby and C. For example, if you look at ext/digest/sha2/lib/sha2.rb you'll see that initialize is just calling Digest::SHA256. But there's no sha256.rb file to be found at ext/digest/sha2/lib. That's because it's defined by ext/digest/sha2/sha2init.c, with methods defined in ext/digest/sha2/sha2.c.
One other possible solution would be to marshal the data to a bytestream but that isn't possible with Digest::SHA2 objects:
Marshal.dump(Digest::SHA2.new)
TypeError: no _dump_data is defined for class Digest::SHA256
Someone else asked a similar question at Can I serialize a ruby Digest::SHA1 instance object? that was not answered. A possible solution for SHA1 digests was listed at https://gist.github.com/parameme/2280705, and you may be able to adapt it, but that gist is 9 years old and the Ruby version at the time was 1.9.3, so it's possible that it will not work on Ruby 2.7.
All my research indicates that you will have to recalculate the hash to get the object to the desired state.

check if hash keys exist in ruby [duplicate]

Ruby 2.3 introduces a new method on Array and Hash called dig. The examples I've seen in blog posts about the new release are contrived and convoluted:
# Hash#dig
user = {
user: {
address: {
street1: '123 Main street'
}
}
}
user.dig(:user, :address, :street1) # => '123 Main street'
# Array#dig
results = [[[1, 2, 3]]]
results.dig(0, 0, 0) # => 1
I'm not using triple-nested flat arrays. What's a realistic example of how this would be useful?
UPDATE
It turns out these methods solve one of the most commonly-asked Ruby questions. The questions below have something like 20 duplicates, all of which are solved by using dig:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
Ruby Style: How to check whether a nested hash element exists
In our case, NoMethodErrors due to nil references are by far the most common errors we see in our production environments.
The new Hash#dig allows you to omit nil checks when accessing nested elements. Since hashes are best used for when the structure of the data is unknown, or volatile, having official support for this makes a lot of sense.
Let's take your example. The following:
user.dig(:user, :address, :street1)
Is not equivalent to:
user[:user][:address][:street1]
In the case where user[:user] or user[:user][:address] is nil, this will result in a runtime error.
Rather, it is equivalent to the following, which is the current idiom:
user[:user] && user[:user][:address] && user[:user][:address][:street1]
Note how it is trivial to pass a list of symbols that was created elsewhere into Hash#dig, whereas it is not very straightforward to recreate the latter construct from such a list. Hash#dig allows you to easily do dynamic access without having to worry about nil references.
Clearly Hash#dig is also a lot shorter.
One important point to take note of is that Hash#dig itself returns nil if any of the keys turn out to be, which can lead to the same class of errors one step down the line, so it can be a good idea to provide a sensible default. (This way of providing an object which always responds to the methods expected is called the Null Object Pattern.)
Again, in your example, an empty string or something like "N/A", depending on what makes sense:
user.dig(:user, :address, :street1) || ""
One way would be in conjunction with the splat operator reading from some unknown document model.
some_json = JSON.parse( '{"people": {"me": 6, ... } ...}' )
# => "{"people" => {"me" => 6, ... }, ... }
a_bunch_of_args = response.data[:query]
# => ["people", "me"]
some_json.dig(*a_bunch_of_args)
# => 6
It's useful for working your way through deeply nested Hashes/Arrays, which might be what you'd get back from an API call, for instance.
In theory it saves a ton of code that would otherwise check at each level whether another level exists, without which you risk constant errors. In practise you still may need a lot of this code as dig will still create errors in some cases (e.g. if anything in the chain is a non-keyed object.)
It is for this reason that your question is actually really valid - dig hasn't seen the usage we might expect. This is commented on here for instance: Why nobody speaks about dig.
To make dig avoid these errors, try the KeyDial gem, which I wrote to wrap around dig and force it to return nil/default if any error crops up.

Is there a way to convert an object to json or other printable format?

I have an object, and I want to dump all its information.
For debugging purpose, can I convert it to json or other suitable format?
I know using p object, sometimes can print out all its information; but not always. So I am asking is there other ways when p object becomes invalid
Try pry
It is excellent for exploring objects. Especially large objects because it has paging. The objects are also color coded to make it more readable.
Steps:
install pry
Add require 'pry' to the script file you want to debug
Add binding.pry below the object declaration of anywhere the object is in scope
Run your script
This will pop open the pry console with access to your object
Type in the object name
'ls object' will list all the instance variables of the object
There's couple ways you can go. Using json from the standard lib is one way to convert an object to json.
this converts an object in ruby to a json string:
require "json"
h = Hash.new(name: "example")
JSON.dump(h)
But you seem to be wanting to inspect an object in detail. The best solution is probably the "Pry" gem that others have suggested if you really need a lot of detail.
so after installing pry you can "cd" into objects and inspect instance variables public/private methods and the source code of methods/classes, etc. its really great stuff.
require "pry"
cd SomeObject
ls # this shows you everything defined in the object.
The problem with object.inspect that others have suggested is that it can be overriden, often is, and thus will oft not show you enough information. So it depends on what you want to find out.
puts o.instance_variables #=> shows all an objects instance variable names
puts o.instance_variable_get :#some_var #=> returns the value held by #some_var
puts o.methods - Object.methods #=> roughly speaking, shows you the methods defined on an object itself and not inheritted from parent objects
Unfortunately there's not a perfect answer here, but for debugging purposes I personally think nothing beats out pry especially with the pry debugger addon gem (forgot actual name) that allows you to step through the call stack.
You can use "inspect" : "Returns a string containing a human-readable representation of obj. By default, show the class name and the list of the instance variables and their values (by calling inspect on each of them). "
Example:
puts object.inspect
you can try puts my_object.as_json.to_json

ruby setting variable versus using variable

I'm somewhat new to ruby so there may be an easy solution to this.
But basically I want to reuse an object #result, so that when I execute a method on it (filter) I continue to be using the original object. However, as I run the method, the object itself seems to be changing.
The object (#result) is RDF::Query::Solutions class
http://rdf.rubyforge.org/RDF/Query/Solutions.html#filter-instance_method
#result = rdf_query(query) # solutions object
At this point the #result contains all the solutions, approximately 30 results
#pubinfo = #result.filter(:ptype => RDF::URI("http://scta.info/pubInfo"))
At this point #result becomes equivalent to what I want only #pubinfo to be. There are only 5 or so results
#contentinfo = #result.filter(:ptype => RDF::URI("http://scta.info/contentInfo"))
at this point #contentinfo comes up nil because the filter is actually on the solutions left from the previous filter. But i wanted to run this filter on the original contents of #result
#linkinginfo = #result.filter(:ptype => RDF::URI("http://scta.info/linkingInfo"))
Again predictable the #linking is 'nil' because #result was set to nil in the previous filter. But I don't want #result changing.
Please help.
update
Look what happens if i try the following
#pubinfo = #result
#pubinfo2 = #pubinfo.filter(:ptype => RDF::URI("http://scta.info/pubInfo"))
binding.pry
At this point #result = has been filtered. Why should should #result be affected at all by what I do to #pubinfo. In other words, how do i make #pubinfo a mere copy or duplicate of #result so that one is not affected by the other??
If you read the documentation:
This method returns an undefined value.
Filters this solution sequence by the given criteria.
This is quite vague, I agree, but one thing stands out - it returns an undefined value, from this I conclude that this is a destructive method, which changes the current object rather than returns a new object with the result of the filter. Another hint to this is that it is Also known as: filter!, since methods ending in ! are by convention destructive in ruby.
Looking at the source code verified this conclusion, as it uses reject! in the code.
As to solutions on how to do it properly - I'm not familiar with this library, and it has proven quite hard to try and figure it out from the documentation, I suggest you find a way to do one of the following (ordered from most recommended, down to last fallback):
Find a non-destructive API
Find a dup or clone API
Re-query before each filter...
And maybe try to contact the author to provide his own recommendation...

Perils and caveats of Kernel::eval in Ruby?

I'm using Ruby 1.9.2 p180.
I'm writing a continuous evaluation tool for Rubyvis (to be part of SciRuby). Basically, you set up the Rubyvis::Panel in your input file (e.g., test.rb), and this SciRuby class (Plotter) watches test.rb for modifications. When there's a change, SciRuby runs the script through eval.
The script works if I run it from the command line, but when executed through eval, the plot is wrong -- a straight line, as if all the data is gone, instead of what you see here. Note: Previously, it said here that the SVG was different -- but it turns out this was the result of REXML being loaded instead of nokogiri.
Here are the test scripts and eval code. Most produce the straight line (with exceptions described in the edit section below).
I haven't the faintest how this is happening.
I have a few ideas as to why it might be happening, but no clue as to the mechanism.
Hypotheses:
eval doesn't allow deep copies to be made. Objects that are taken from eval are missing pieces in certain contexts, particularly when lambda is used to process the data into the correct format for the plot.
For some reason, eval is not honoring the bundled dep list when require is called -- maybe the wrong version of nokogiri is being used in my binding?
Some other required library (perhaps RSVG?) has overloaded some method Rubyvis uses.
Has anyone seen anything like this before? I'm sort of feeling around in the dark -- at a total loss as to where to begin troubleshooting.
Edit 9/15/11: new information
It seems that the call to OpenStruct.new is causing the problem.
If I define data as a list of lists, data = pv.range(0,10,0.1).map { |d| [d,Math.sin(d)+2+rand()] }, it works well.
But when data is defined as a list of OpenStructs, the following code gives incorrect output:
data = pv.range(0, 10, 0.1).map {|x|
o = OpenStruct.new({:x=> x, :y=> Math.sin(x) + 2+rand()})
STDERR.puts o.inspect # Output is correct.
o
}
STDERR.puts "size of data: #{data.size}"
STDERR.puts "first x = #{data.first.x}" # Output is first x = 0.0
STDERR.puts "first y = #{data.first.y}" # Output is first y = (WRONG)
I can even induce an error if I use collect when assigning the data, e.g.,
vis.add(pv.Line).data(data.collect { |d| [d.x,d.y] }
plotter.rb:88:in `block in <main>': undefined method `x' for [0.0, nil]:Array (NoMethodError)
versus no error with vis.add(pv.Line).data(data). The error appears to originate from the call to eval("vis.render()", bind) in my app's source (not in the plot script).
It turns out that if I just use a hash, e.g., {:x => x, :y => Math.sin(x)}, that works fine. But when I explicitly say Hash.new({:x => x, :y => Math.sin(x)}), that gives an error regardless of how I call vis.data:
rubyvis/lib/rubyvis/internals.rb:184:in `each': comparison of Hash with Hash failed (ArgumentError)
So the difference is in how my data is assigned. The question is: why?
Copies of the inputs are available in the original gist. Thanks for your help.
It turns out that if I just use a hash, e.g., {:x => x, :y =>
Math.sin(x)}, that works fine. But when I explicitly say Hash.new({:x
=> x, :y => Math.sin(x)}), that gives an error regardless of how I
call vis.data:
First of all, your call to Hash.new is wrong. Hash.new takes a parameter that's the default value of the hash.
I wanted to post this as a comment, not an answer;
Have you tried load instead of eval?

Resources