Fetching all the values for keys matching a regular expression - ruby

I'm looking for a Ruby in-memory key-value store that allows me to select all values for the keys that match a regular expression.
I have looked online but I can't find something the does what I need.
Any suggestion?
Thanks
Update
After reviewing my question I noticed I wasn't probably very clear so, also because someone of you guys asked got it, here an example.
I'm currently using Daybreak in my app so I use it for the example but it does not work.
require 'daybreak'
db = Daybreak::DB.new "example.db"
db['prefix_foo'] = 'first'
db['prefix_bar'] = 'second'
db['doo'] = 'third'
db.magic('prefix') #=> [ db['prefix_foo'], db['prefix_bar']]
Or
db.magic('prefix') #=> ['prefix_foo', 'prefix_bar']
I'd rather not to use a "naked" hash.
Thanks again for your help.

str = {:make => "bmw", :year => "2003"}
str.select{|k,v| k =~ /ak/}
#=> {:make=>"bmw"}
str.select{|k,v| k =~ /ak/}.values #=> get only values
#=> ["bmw"]

Related

Object attributes to JavaScript-like hash?

This is kind of an odd question, but I don't .......
I overcomplicated the original question. If you want to see the original question, look through the previous edits. Here's my revised question by combining my two previous questions, as simple as I can explain it:
I have an object. The object can have (x) amount of fields and all of the fields and values can be different. Example:
#<User name="John", height=75> or #<Comment title="First!">
I'm using a gem/db requires a specific format for queries. This is the format that the query MUST have: CREATE (u:User{attribute: "Some att.", another_att: 32}) and so on and so forth. Notice the JavaScript-like hash it uses for its values.
I'm trying to interpolate an object's attributes into the query. But I don't know how to map the correct fields and values into the query. Here's an example of what I start with and what I want to end with:
object = #<User name="John", height=75> =>
"CREATE (u:User{name: "John", height: 75})"
What's the simplest way to achieve this? Thanks to everyone who's helped so far.
Note that it is possible to convert the attributes to a Ruby hash: {:name => "John", :height => 75}, (as explained in the original question) but it was too confusing to change that hash to the syntax in the query, so I've backtracked and simplified my question.
It is very unlikely that the literal is the problem. The JSON-style syntax
was introduced in Ruby 1.9 as a literal abbreviation for the longer
"hashrocket" style.
> {name: 'John'} == {:name => 'John'}
=> true
Figured it out by going through the Ruby docs. It was way simpler than it seemed. The .collect method (or map) can be used to map each value and field to an interpolated string that can be put into a query. Example:
hash = {first_name: 'John', last_name: 'Smith'}
hash.collect {|k, v| "#{k}: #{v}"}
=> ["first_name: John", "last_name: Smith"]
This doesn't make sense. There has to be something else going on here.
A hash is a hash is a hash, it doesn't matter what syntax you used to create it, it's still the exact same hash. Those four are 100% equivalent (and if they aren't, that's a bug in your Ruby implementation):
hash = { name: 'John' }
hash = { :name => 'John' }
hash = {}
hash[:name] = 'John'
hash = Hash.new
hash[%Q|name|.to_sym] = %w#John#.first
There is absolutely no difference between them. There is no such thing as a "Hashrocket Hash" or "JSON-style Hash". There is a difference between the literals used to construct those hashes, but that difference only exists at parse time. At runtime, they are just as identical as 16, 0x10 and 020 are.

How do I generate constants to access Ruby array elements?

I use an array to store fieldvalues. To easily add and access elements I use constants as element identifiers.
Until now I did this by hand like this:
stages = ["lidnummer","aardf","prest","dt_prest","aantal","bedrag","verstrekker","foutcode"]
values = ["it","can","be","anything",0,5.3,nil,88]
LIDNUMMER,AARDF,PREST,DT_PREST,AANTAL,BEDRAG,VERSTREKKER,FOUTCODE = 0,1,2,3,1,5,6,7
p values[AARDF] => "can"
Now I have automated this like:
stages = ["lidnummer","aardf","prest","dt_prest","aantal","bedrag","verstrekker","foutcode"]
values = ["it","can","be","anything",0,5.3,nil,88]
stages.each do |c|
eval "#{c.upcase} = #{stages.index(c)}"
end
p values[AARDF] => "can"
But I suppose there is a better Ruby-way to do this, and perhaps without the eval, are there suggestions?
This the easiest I can think of if you insist on doing it the way you described and not using hashes:
stages.zip(values) { |stage, value| Object.const_set(stage.upcase, value) }
values[BEDRAG] #=> 5
Personally I'd just build a hash, but you know your requirements better than I do:
Hash[stages.map(&:upcase).zip(values)]
#=> {"LIDNUMMER"=>0, "AARDF"=>1, "PREST"=>2, "DT_PREST"=>3, "AANTAL"=>4, "BEDRAG"=>5, "VERSTREKKER"=>6, "FOUTCODE"=>7}
Yes, use a Hash and Symbols.
stages = {:aardf => "aardf", :prest => "prest", ...}
stages[:aardf]
For legacy, use
AARDF = :aardf
and
stages[AARDF]
will still work.
other way you may get interested -
stages = ["lidnummer","aardf","prest","dt_prest","aantal","bedrag","verstrekker","foutcode"]
values = [0,1,2,3,4,5,6,7]
stages = stages.zip(values).inject({}) {|h, (k,v)| h[k.upcase]=v;h}
=> {"LIDNUMMER"=>0, "FOUTCODE"=>7, "BEDRAG"=>5, "VERSTREKKER"=>6, "AANTAL"=>4, "PREST"=>2, "AARDF"=>1, "DT_PREST"=>3}
p stages['AARDF'] #=> 1
Thanks all, i learned a lot of this.
Michael was the nearest with his answer but not right (the values array can contain anything, normally it is not the order of the element).
I managed to combine the different techniques here presented and came up with the following.
stages = ["lidnummer","aardf","prest","dt_prest","aantal","bedrag","verstrekker","foutcode"]
values = ["it","can","be","anything",0,5.3,nil,88]
stages.each_with_index{|c,i|Object::const_set(c.upcase, i)}
p values[AARDF] => "it"
p values[BEDRAG] => 5.3
If i use a Hash it is more error sensitive and i would end using
p values[hash["AARDF"]]
which is not as smooth

Best way to extract the relevant info from String?

I have an array of strings that are supposed to be used as constraints when creating a new class.
They look like this:
constraint :name, 'name.size > 0'
constraint :name, 'name =~ /^[A-Z]/'
And are, as you can see, made up of 'name' which is going to be an attribute (and will have methods for get/set the values it holds)
the constraint itself are valid ruby booleans.
What is the best way to get the info needed from these strings, and to implement them in the methods?
As of now i'm trying to chop up the string, something like this:
y = String.index("'")
x = String.length
newstr = String[x,y]
and so on, but this really feels like i'm making it harder than it is..
Try the Split method. If you want only the information after the ' use it like this:
username = "abcd'hijk" => "abcd'hijk"
username.split("'").last => "hijk"
Different ways
a = "abcd'hijk"
a.split("'").last #=> hijk
a[a.index("'")+1 .. -1] #=> hijk
a =~ /'(.+)$/
puts $1 #=> hijk

Can I or SHOULD I find an object by the object_id attribute in ruby?

When I make a new object, let's say
o = Object.new
This object has an id,
o.object_id
#=> ########
I also make several other objects, using the Object class. What would be the best way to have ruby find the object 'o' by using the object_id attribute? I am thinking in terms of something like
search_id = o.object_id
search_result = Object.find(search_id)
Where 'search_results' would be the object corresponding to 'search_id'. Also, I would definitely appreciate an altogether different approach to indexing objects and retrieving them by a guid or something. Thanks so much!
Hah, well I guess I really just need to think about this in the context of a database and just use MySQL queries or those of whatever DB I choose to find the object. The more I think about it, the only possible things that would be accessible through this imaginary 'find()' method would be things that are newly created or 'active'? Sorry for making this a crappy question.
Yes, you can:
irb(main):002:0> s1 = "foo"
#=> "foo"
irb(main):003:0> s2 = ObjectSpace._id2ref(s1.object_id)
#=> "foo"
irb(main):004:0> s2.object_id == s1.object_id
#=> true
irb(main):005:0> s2[0] = "z"
#=> "z"
irb(main):006:0> s1
#=> "zoo"
Should you do this? I'll leave that up to you. There are less geeky ways to store an object with a serializable id (e.g. in an Array and returning the index). One problem you may run into is that if the only 'reference' you keep to an object is the object_id, the object can be collected by GC when you're not looking.

Ruby: How to loop through an object that may or may not be an array?

I have an each method that is run on some user-submitted data.
Sometimes it will be an array, other times it won't be.
Example submission:
<numbers>
<number>12345</number>
</numbers>
Another example:
<numbers>
<number>12345</number>
<number>09876</number>
</numbers>
I have been trying to do an each do on that, but when there is only one number I get a TypeError (Symbol as array index) error.
I recently asked a question that was tangentally similar. You can easily force any Ruby object into an array using Array.
p Array([1,2,3]) #-> [1,2,3]
p Array(123) #-> [123]
Of course, arrays respond to each. So if you force everying into an array, your problem should be solved.
A simple workaround is to just check if your object responds to :each; and if not, wrap it in an array.
irb(main):002:0> def foo x
irb(main):003:1> if x.respond_to? :each then x else [x] end
irb(main):005:1> end
=> nil
irb(main):007:0> (foo [1,2,3]).each { |x| puts x }
1
2
3
=> [1, 2, 3]
irb(main):008:0> (foo 5).each { |x| puts x }
5
=> [5]
It looks like the problem you want to solve is not the problem you are having.
TypeError (Symbol as array index)
That error tells me that you have an array, but are treating it like a hash and passing in a symbol key when it expects an integer index.
Also, most XML parsers provide child nodes as array, even if there is only one. So this shouldn't be necesary.
In the case of arguments to a method, you can test the object type. This allows you to pass in a single object or an array, and converts to an array only if its not one so you can treat it identically form that point on.
def foo(obj)
obj = [obj] unless obj.is_a?(Array)
do_something_with(obj)
end
Or something a bit cleaner but more cryptic
def foo(obj)
obj = [*obj]
do_something_with(obj)
end
This takes advantage of the splat operator to splat out an array if it is one. So it splats it out (or doesn't change it) and you can then wrap it an array and your good to go.
I was in the same position recently except the object I was working with was either a hash or an array of hashes. If you are using Rails, you can use Array.wrap because Array(hash) converts hashes to an array.
Array({foo: "bar"}) #=> [[:foo, "bar"]]
Array.wrap({foo: "bar"}) #=> [{:foo=>"bar"}]
Array.wrap(123) #=> [123]
Array.wrap([123]) #=> [123]
I sometimes use this cheap little trick:
[might_be_an_array].flatten.each { |x| .... }
Use the splat operator:
[*1] # => [1]
[*[1,2]] # => [1,2]
Like Mark said, you're looking for "respond_to?" Another option would be to use the conditional operator like this:
foo.respond_to? :each ? foo.each{|x| dostuff(x)} : dostuff(foo);
What are you trying to do with each number?
You should try to avoid using respond_to? message as it is not a very object oriented aproach.
Check if is it possible to find in the xml generator code where it is assigning an integer value when there is just one <"number"> tag and modify it to return an array.
Maybe it is a complex task, but I would try to do this in order to get a better OO design.
I don't know much anything about ruby, but I'd assume you could cast (explicitly) the input to an array - especially given that if the input is simply one element longer it's automatically converted to an array.
Have you tried casting it?
If your input is x, use x.to_a to convert your input into an array.
[1,2,3].to_a
=> [1, 2, 3]
1.to_a
=> [1]
"sample string".to_a
=> ["sample string"]
Edit: Newer versions of Ruby seem to not define a default .to_a for some standard objects anymore. You can always use the "explicit cast" syntax Array(x) to achieve the same effect.

Resources