2012-01-07 18:58:16 +00:00
|
|
|
# Hashie [![Build Status](https://secure.travis-ci.org/intridea/hashie.png)](http://travis-ci.org/intridea/hashie) [![Dependency Status](https://gemnasium.com/intridea/hashie.png)](https://gemnasium.com/intridea/hashie)
|
2009-09-03 01:32:57 +00:00
|
|
|
|
2009-09-06 04:27:54 +00:00
|
|
|
Hashie is a growing collection of tools that extend Hashes and make
|
|
|
|
them more useful.
|
2009-09-03 01:32:57 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Installation
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2010-03-05 17:51:58 +00:00
|
|
|
Hashie is available as a RubyGem:
|
2009-11-12 14:08:55 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```bash
|
|
|
|
$ gem install hashie
|
|
|
|
```
|
2009-11-12 14:08:55 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Hash Extensions
|
|
|
|
|
2013-04-07 00:52:53 +00:00
|
|
|
The library is broken up into a number of atomically includeable Hash
|
|
|
|
extension modules as described below. This provides maximum flexibility
|
|
|
|
for users to mix and match functionality while maintaining feature parity
|
|
|
|
with earlier versions of Hashie.
|
2011-08-02 05:34:29 +00:00
|
|
|
|
2011-08-02 15:44:23 +00:00
|
|
|
Any of the extensions listed below can be mixed into a class by
|
|
|
|
`include`-ing `Hashie::Extensions::ExtensionName`.
|
|
|
|
|
|
|
|
### Coercion
|
2011-08-02 05:34:29 +00:00
|
|
|
|
|
|
|
Coercions allow you to set up "coercion rules" based either on the key
|
|
|
|
or the value type to massage data as it's being inserted into the Hash.
|
|
|
|
Key coercions might be used, for example, in lightweight data modeling
|
|
|
|
applications such as an API client:
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class Tweet < Hash
|
|
|
|
include Hashie::Extensions::Coercion
|
|
|
|
coerce_key :user, User
|
|
|
|
end
|
2012-03-25 13:05:32 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
user_hash = {:name => "Bob"}
|
|
|
|
Tweet.new(:user => user_hash)
|
|
|
|
# => automatically calls User.coerce(user_hash) or
|
|
|
|
# User.new(user_hash) if that isn't present.
|
|
|
|
```
|
2011-08-02 05:34:29 +00:00
|
|
|
|
|
|
|
Value coercions, on the other hand, will coerce values based on the type
|
|
|
|
of the value being inserted. This is useful if you are trying to build a
|
|
|
|
Hash-like class that is self-propagating.
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class SpecialHash < Hash
|
|
|
|
include Hashie::Extensions::Coercion
|
|
|
|
coerce_value Hash, SpecialHash
|
2012-03-25 13:05:32 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
def initialize(hash = {})
|
|
|
|
super
|
|
|
|
hash.each_pair do |k,v|
|
|
|
|
self[k] = v
|
2011-08-02 05:34:29 +00:00
|
|
|
end
|
2013-12-02 21:34:53 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
```
|
2011-08-02 05:34:29 +00:00
|
|
|
|
2011-08-02 15:44:23 +00:00
|
|
|
### KeyConversion
|
2011-08-02 05:34:29 +00:00
|
|
|
|
|
|
|
The KeyConversion extension gives you the convenience methods of
|
|
|
|
`symbolize_keys` and `stringify_keys` along with their bang
|
|
|
|
counterparts. You can also include just stringify or just symbolize with
|
|
|
|
`Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
|
|
|
|
|
2011-08-02 15:44:23 +00:00
|
|
|
### MergeInitializer
|
|
|
|
|
2011-08-02 21:03:21 +00:00
|
|
|
The MergeInitializer extension simply makes it possible to initialize a
|
|
|
|
Hash subclass with another Hash, giving you a quick short-hand.
|
|
|
|
|
2011-08-02 15:44:23 +00:00
|
|
|
### MethodAccess
|
2011-08-02 05:34:29 +00:00
|
|
|
|
|
|
|
The MethodAccess extension allows you to quickly build method-based
|
|
|
|
reading, writing, and querying into your Hash descendant. It can also be
|
|
|
|
included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
|
|
|
|
`Hashie::Extensions::MethodWriter` and `Hashie::Extensions::MethodQuery`
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class MyHash < Hash
|
|
|
|
include Hashie::Extensions::MethodAccess
|
|
|
|
end
|
2012-03-25 13:05:32 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
h = MyHash.new
|
|
|
|
h.abc = 'def'
|
|
|
|
h.abc # => 'def'
|
|
|
|
h.abc? # => true
|
|
|
|
```
|
2011-08-02 05:34:29 +00:00
|
|
|
|
2011-08-02 21:03:21 +00:00
|
|
|
### IndifferentAccess
|
|
|
|
|
|
|
|
This extension can be mixed in to instantly give you indifferent access
|
|
|
|
to your Hash subclass. This works just like the params hash in Rails and
|
|
|
|
other frameworks where whether you provide symbols or strings to access
|
|
|
|
keys, you will get the same results.
|
|
|
|
|
|
|
|
A unique feature of Hashie's IndifferentAccess mixin is that it will
|
|
|
|
inject itself recursively into subhashes *without* reinitializing the
|
|
|
|
hash in question. This means you can safely merge together indifferent
|
|
|
|
and non-indifferent hashes arbitrarily deeply without worrying about
|
|
|
|
whether you'll be able to `hash[:other][:another]` properly.
|
|
|
|
|
2012-03-25 13:05:32 +00:00
|
|
|
### DeepMerge
|
|
|
|
|
|
|
|
This extension allow you to easily include a recursive merging
|
|
|
|
system to any Hash descendant:
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class MyHash < Hash
|
|
|
|
include Hashie::Extensions::DeepMerge
|
|
|
|
end
|
2012-03-25 13:05:32 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
h1 = MyHash.new
|
|
|
|
h2 = MyHash.new
|
2012-03-25 13:05:32 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
|
|
|
|
h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
|
2011-08-02 05:34:29 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
|
|
|
|
h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
|
|
|
|
```
|
2011-08-02 05:34:29 +00:00
|
|
|
|
|
|
|
## Mash
|
2009-11-12 14:08:55 +00:00
|
|
|
|
|
|
|
Mash is an extended Hash that gives simple pseudo-object functionality
|
|
|
|
that can be built from hashes and easily extended. It is designed to
|
2011-07-02 22:10:15 +00:00
|
|
|
be used in RESTful API libraries to provide easy object-like access
|
2009-11-12 14:08:55 +00:00
|
|
|
to JSON and XML parsed hashes.
|
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
### Example:
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
mash = Hashie::Mash.new
|
|
|
|
mash.name? # => false
|
|
|
|
mash.name # => nil
|
|
|
|
mash.name = "My Mash"
|
|
|
|
mash.name # => "My Mash"
|
|
|
|
mash.name? # => true
|
|
|
|
mash.inspect # => <Hashie::Mash name="My Mash">
|
|
|
|
|
|
|
|
mash = Mash.new
|
|
|
|
# use bang methods for multi-level assignment
|
|
|
|
mash.author!.name = "Michael Bleigh"
|
|
|
|
mash.author # => <Hashie::Mash name="Michael Bleigh">
|
|
|
|
|
|
|
|
mash = Mash.new
|
|
|
|
# use under-bang methods for multi-level testing
|
|
|
|
mash.author_.name? # => false
|
|
|
|
mash.inspect # => <Hashie::Mash>
|
|
|
|
```
|
2012-04-16 03:23:59 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
**Note:** The `?` method will return false if a key has been set
|
2010-08-10 15:05:52 +00:00
|
|
|
to false or nil. In order to check if a key has been set at all, use the
|
2011-08-02 05:34:29 +00:00
|
|
|
`mash.key?('some_key')` method instead.
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Dash
|
2009-11-12 14:08:55 +00:00
|
|
|
|
|
|
|
Dash is an extended Hash that has a discrete set of defined properties
|
|
|
|
and only those properties may be set on the hash. Additionally, you
|
2011-07-23 18:25:38 +00:00
|
|
|
can set defaults for each property. You can also flag a property as
|
2012-02-13 09:11:59 +00:00
|
|
|
required. Required properties will raise an exception if unset.
|
2009-11-12 14:08:55 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
### Example:
|
2009-11-12 14:08:55 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class Person < Hashie::Dash
|
|
|
|
property :name, :required => true
|
|
|
|
property :email
|
|
|
|
property :occupation, :default => 'Rubyist'
|
|
|
|
end
|
|
|
|
|
|
|
|
p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
|
|
|
|
|
|
|
|
p = Person.new(:name => "Bob")
|
|
|
|
p.name # => 'Bob'
|
|
|
|
p.name = nil # => ArgumentError: The property 'name' is required for this Dash.
|
|
|
|
p.email = 'abc@def.com'
|
|
|
|
p.occupation # => 'Rubyist'
|
|
|
|
p.email # => 'abc@def.com'
|
|
|
|
p[:awesome] # => NoMethodError
|
|
|
|
p[:occupation] # => 'Rubyist'
|
|
|
|
```
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Trash
|
2010-08-10 15:07:54 +00:00
|
|
|
|
|
|
|
A Trash is a Dash that allows you to translate keys on initialization.
|
|
|
|
It is used like so:
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class Person < Hashie::Trash
|
|
|
|
property :first_name, :from => :firstName
|
|
|
|
end
|
|
|
|
```
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2010-08-10 15:07:54 +00:00
|
|
|
This will automatically translate the <tt>firstName</tt> key to <tt>first_name</tt>
|
|
|
|
when it is initialized using a hash such as through:
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
Person.new(:firstName => 'Bob')
|
|
|
|
```
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2012-04-17 11:12:05 +00:00
|
|
|
Trash also supports translations using lambda, this could be useful when dealing with
|
|
|
|
external API's. You can use it in this way:
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
class Result < Hashie::Trash
|
|
|
|
property :id, :transform_with => lambda { |v| v.to_i }
|
|
|
|
property :created_at, :from => :creation_date, :with => lambda { |v| Time.parse(v) }
|
|
|
|
end
|
|
|
|
```
|
2012-04-17 11:12:05 +00:00
|
|
|
|
|
|
|
this will produce the following
|
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
result = Result.new(:id => '123', :creation_date => '2012-03-30 17:23:28')
|
|
|
|
result.id.class # => Fixnum
|
|
|
|
result.created_at.class # => Time
|
|
|
|
```
|
2012-04-17 11:12:05 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Clash
|
2010-03-05 17:51:58 +00:00
|
|
|
|
|
|
|
Clash is a Chainable Lazy Hash that allows you to easily construct
|
|
|
|
complex hashes using method notation chaining. This will allow you
|
|
|
|
to use a more action-oriented approach to building options hashes.
|
|
|
|
|
|
|
|
Essentially, a Clash is a generalized way to provide much of the same
|
|
|
|
kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
|
|
|
|
provide.
|
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
### Example
|
2010-03-05 17:51:58 +00:00
|
|
|
|
2013-12-02 21:34:53 +00:00
|
|
|
```ruby
|
|
|
|
c = Hashie::Clash.new
|
|
|
|
c.where(:abc => 'def').order(:created_at)
|
|
|
|
c # => {:where => {:abc => 'def'}, :order => :created_at}
|
|
|
|
|
|
|
|
# You can also use bang notation to chain into sub-hashes,
|
|
|
|
# jumping back up the chain with _end!
|
|
|
|
c = Hashie::Clash.new
|
|
|
|
c.where!.abc('def').ghi(123)._end!.order(:created_at)
|
|
|
|
c # => {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}
|
|
|
|
|
|
|
|
# Multiple hashes are merged automatically
|
|
|
|
c = Hashie::Clash.new
|
|
|
|
c.where(:abc => 'def').where(:hgi => 123)
|
|
|
|
c # => {:where => {:abc => 'def', :hgi => 123}}
|
|
|
|
```
|
2009-11-12 14:08:55 +00:00
|
|
|
|
2013-02-14 20:49:59 +00:00
|
|
|
## Contributing
|
2011-07-02 22:10:15 +00:00
|
|
|
|
2013-02-14 20:49:59 +00:00
|
|
|
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
2009-09-03 01:32:57 +00:00
|
|
|
|
2011-08-02 05:34:29 +00:00
|
|
|
## Copyright
|
2009-09-03 01:32:57 +00:00
|
|
|
|
2014-03-30 23:04:00 +00:00
|
|
|
Copyright (c) 2009-2014 Intridea, Inc. (http://intridea.com/) and [contributors](https://github.com/intridea/hashie/graphs/contributors).
|
|
|
|
|
|
|
|
MIT License. See [LICENSE](LICENSE) for details.
|