mobj

Some utilities that I keep using.

Of particular note may be the string tokenizer/path walker.

Example

Read the code.

No, really. Give me some examples, dork.

Fine.

Toking Up

This is really the most useful part of the entire library, when you get right down to it. String is given a method called "tokenize" that allows it's contents to be split up into a structured path of tokens. This tokenized path can then be used to do some pretty amazing things in terms of walking through arbitrarily complex trees of data. There's a convenience method on String called "walk" that handles this all for you.

For example, given this object:

obj = {
    name: { first: "Joe", last: "Smith" },
    ids: [ 1, 3, 5, 16, 941, 13, 100, 3, 0, 104 ],
    auth_tokens: [ { provider: { name: "example.com", id:123 },
                     token: { auth: "123456", expire: "10-20-2012" } },
                   { provider: { name: "site.com", id:265 },
                     token: { authentication_token: "891011", date: "10-20-2013" } }
    ],
    primary_key: { path: "auth_tokens.provider" }
}

Easily traverse it's data using rules embedded into a simple string, like so:

# Walk a simple object path:
"name.first".walk(obj)
#=> "Joe"

# Select multiple items out of an object:
"name.first,last".walk(obj)
#=> ["Joe", "Smith"]

# Or indexes (and ranges) in an array:
"ids[1, 3, 5..7, 9+]".walk(obj)
#=> [3, 16, 13, 100, 3, 104]

# Use regular expressions or even method calls as selection keys:
"auth_tokens.token./^auth/.*to_i".walk(obj)
#=> [ 123456, 891011 ]

# Choose the first element that doesn't return nil:
"auth_tokens.token.expire|date".walk(obj)
#=> [ "10-20-2012", "10-20-2013" ]

# Provide default values when everything is nil:
"/auth/.provider,token.auth|authentication_token|~N/A".walk(obj)
#=> ["N/A", "N/A", "123456", "891011"]

# Even look up keys based on the values in other fields:
"{{primary_key.path}}.id".walk(obj)
#=> [123, 265]

And much, much more, though you'd probably want to check out the tests to see how it really works.

Much Ado about Nulling

Every so often you find yourself in a situation where you want nil to behave like "null" (i.e. you want it to silently allow unknown method calls to simply do nothing instead of throwing and exception). All classes are now given a "null!" method that alters the behavior of nil for the remainder of the line:

obj = FooObject.new

if obj.null!.foo.bar.baz
  puts "Acts like normal"
end

obj = nil

if obj.null!.foo.bar.baz
  puts "Won't throw and exception and evaluates to nil"
end

if obj.foo.bar.baz
  puts "Will throw an exception as normal"
end

When you just want to be contrary

Sometimes you just want to write everything in dot notation for no reason. Or maybe you have a reason, and that reason is impressing your co workers with your ruby tricks:

if foo && foo.bar
  foo.baz
else
  foo.biz
end

... becomes ...

foo.when.bar.then.baz.else.biz

Sequestration, HashEx, MatchEx, etc

Found myself writing these things sooo many times that I just dumped them into my package of stuff:

foo.compact.size == 1 ? foo.compact.first : foo.compact

... becomes ...

foo.sequester!

Hash utils:

hash = { symbol: "sym", "string" => "string", :nilval => nil }

hash.symbol == hash[:symbol] == hash[:symbol]
#=> These are equvilent

hash.string == hash[:string] == hash["string"]
#=> These are also equvilent

hash.string?
#=> true

hash.nilval?
#=> false

hash.unknown?
#=> True

Matching stuff:

match = "Joe Bob".match(/(?<first_name>\w+) (?<first_name>)/)

match.to_h
#=> Creates a hash of named captures

match.first_name if match.first_name?
#=> Or just use them directly as method names

"foo,bar,baz".matches(/([^,]+),/) do |match|
  #=> same as "string#scan", but returns the actual MatchData
end

Caveats and such

All of them.