hashie-pre 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ *.gem
7
+ .bundle
8
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format=nested
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - rbx
5
+ - ree
6
+ - ruby-head
7
+ - jruby
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ -m markdown
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hashie-pre (2.0.0.beta)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ growl (1.0.3)
11
+ guard (0.5.1)
12
+ thor (~> 0.14.6)
13
+ guard-rspec (0.4.0)
14
+ guard (>= 0.4.0)
15
+ rake (0.9.2)
16
+ rspec (2.6.0)
17
+ rspec-core (~> 2.6.0)
18
+ rspec-expectations (~> 2.6.0)
19
+ rspec-mocks (~> 2.6.0)
20
+ rspec-core (2.6.4)
21
+ rspec-expectations (2.6.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.6.0)
24
+ thor (0.14.6)
25
+
26
+ PLATFORMS
27
+ java
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ growl
32
+ guard
33
+ guard-rspec
34
+ hashie-pre!
35
+ rake (~> 0.9.2)
36
+ rspec (~> 2.5)
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb})
3
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Intridea, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,232 @@
1
+ **Note:** This documentation is for the unreleased version 2.0 of
2
+ Hashie. See the [1-1-stable branch](https://github.com/intridea/hashie/tree/1-1-stable) for documentation of the released version.
3
+
4
+ # 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)
5
+
6
+ Hashie is a growing collection of tools that extend Hashes and make
7
+ them more useful.
8
+
9
+ ## Installation
10
+
11
+ Hashie is available as a RubyGem:
12
+
13
+ gem install hashie
14
+
15
+ ## Hash Extensions
16
+
17
+ New to version 2.0 of Hashie, the library has been broken up into a
18
+ number of atomically includeable Hash extension modules as described
19
+ below. This provides maximum flexibility for users to mix and match
20
+ functionality while maintaining feature parity with earlier versions of
21
+ Hashie.
22
+
23
+ Any of the extensions listed below can be mixed into a class by
24
+ `include`-ing `Hashie::Extensions::ExtensionName`.
25
+
26
+ ### Coercion
27
+
28
+ Coercions allow you to set up "coercion rules" based either on the key
29
+ or the value type to massage data as it's being inserted into the Hash.
30
+ Key coercions might be used, for example, in lightweight data modeling
31
+ applications such as an API client:
32
+
33
+ class Tweet < Hash
34
+ include Hashie::Extensions::Coercion
35
+ coerce_key :user, User
36
+ end
37
+
38
+ user_hash = {:name => "Bob"}
39
+ Tweet.new(:user => user_hash)
40
+ # => automatically calls User.coerce(user_hash) or
41
+ # User.new(user_hash) if that isn't present.
42
+
43
+ Value coercions, on the other hand, will coerce values based on the type
44
+ of the value being inserted. This is useful if you are trying to build a
45
+ Hash-like class that is self-propagating.
46
+
47
+ class SpecialHash < Hash
48
+ include Hashie::Extensions::Coercion
49
+ coerce_value Hash, SpecialHash
50
+
51
+ def initialize(hash = {})
52
+ super
53
+ hash.each_pair do |k,v|
54
+ self[k] = v
55
+ end
56
+ end
57
+ end
58
+
59
+ ### KeyConversion
60
+
61
+ The KeyConversion extension gives you the convenience methods of
62
+ `symbolize_keys` and `stringify_keys` along with their bang
63
+ counterparts. You can also include just stringify or just symbolize with
64
+ `Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
65
+
66
+ ### MergeInitializer
67
+
68
+ The MergeInitializer extension simply makes it possible to initialize a
69
+ Hash subclass with another Hash, giving you a quick short-hand.
70
+
71
+ ### MethodAccess
72
+
73
+ The MethodAccess extension allows you to quickly build method-based
74
+ reading, writing, and querying into your Hash descendant. It can also be
75
+ included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
76
+ `Hashie::Extensions::MethodWriter` and `Hashie::Extensions::MethodQuery`
77
+
78
+ class MyHash < Hash
79
+ include Hashie::Extensions::MethodAccess
80
+ end
81
+
82
+ h = MyHash.new
83
+ h.abc = 'def'
84
+ h.abc # => 'def'
85
+ h.abc? # => true
86
+
87
+ ### IndifferentAccess
88
+
89
+ This extension can be mixed in to instantly give you indifferent access
90
+ to your Hash subclass. This works just like the params hash in Rails and
91
+ other frameworks where whether you provide symbols or strings to access
92
+ keys, you will get the same results.
93
+
94
+ A unique feature of Hashie's IndifferentAccess mixin is that it will
95
+ inject itself recursively into subhashes *without* reinitializing the
96
+ hash in question. This means you can safely merge together indifferent
97
+ and non-indifferent hashes arbitrarily deeply without worrying about
98
+ whether you'll be able to `hash[:other][:another]` properly.
99
+
100
+ ### DeepMerge (Unimplemented)
101
+
102
+ This extension *will* allow you to easily include a recursive merging
103
+ system to any Hash descendant.
104
+
105
+ ## Mash
106
+
107
+ Mash is an extended Hash that gives simple pseudo-object functionality
108
+ that can be built from hashes and easily extended. It is designed to
109
+ be used in RESTful API libraries to provide easy object-like access
110
+ to JSON and XML parsed hashes.
111
+
112
+ ### Example:
113
+
114
+ mash = Hashie::Mash.new
115
+ mash.name? # => false
116
+ mash.name # => nil
117
+ mash.name = "My Mash"
118
+ mash.name # => "My Mash"
119
+ mash.name? # => true
120
+ mash.inspect # => <Hashie::Mash name="My Mash">
121
+
122
+ mash = Mash.new
123
+ # use bang methods for multi-level assignment
124
+ mash.author!.name = "Michael Bleigh"
125
+ mash.author # => <Hashie::Mash name="Michael Bleigh">
126
+
127
+ mash = Mash.new
128
+ # use under-bang methods for multi-level testing
129
+ mash.author_.name? # => false
130
+ mash.inspect # => <Hashie::Mash>
131
+
132
+ **Note:** The `?` method will return false if a key has been set
133
+ to false or nil. In order to check if a key has been set at all, use the
134
+ `mash.key?('some_key')` method instead.
135
+
136
+ ## Dash
137
+
138
+ Dash is an extended Hash that has a discrete set of defined properties
139
+ and only those properties may be set on the hash. Additionally, you
140
+ can set defaults for each property. You can also flag a property as
141
+ required. Required properties will raise an execption if unset.
142
+
143
+ ### Example:
144
+
145
+ class Person < Hashie::Dash
146
+ property :name, :required => true
147
+ property :email
148
+ property :occupation, :default => 'Rubyist'
149
+ end
150
+
151
+ p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
152
+
153
+ p = Person.new(:name => "Bob")
154
+ p.name # => 'Bob'
155
+ p.name = nil # => ArgumentError: The property 'name' is required for this Dash.
156
+ p.email = 'abc@def.com'
157
+ p.occupation # => 'Rubyist'
158
+ p.email # => 'abc@def.com'
159
+ p[:awesome] # => NoMethodError
160
+ p[:occupation] # => 'Rubyist'
161
+
162
+ ## Trash
163
+
164
+ A Trash is a Dash that allows you to translate keys on initialization.
165
+ It is used like so:
166
+
167
+ class Person < Hashie::Trash
168
+ property :first_name, :from => :firstName
169
+ end
170
+
171
+ This will automatically translate the <tt>firstName</tt> key to <tt>first_name</tt>
172
+ when it is initialized using a hash such as through:
173
+
174
+ Person.new(:firstName => 'Bob')
175
+
176
+ Trash also supports translations using lambda, this could be useful when dealing with
177
+ external API's. You can use it in this way:
178
+
179
+ class Result < Hashie::Trash
180
+ property :id, :transform_with => lambda { |v| v.to_i }
181
+ property :created_at, :from => :creation_date, :with => lambda { |v| Time.parse(v) }
182
+ end
183
+
184
+ this will produce the following
185
+
186
+ result = Result.new(:id => '123', :creation_date => '2012-03-30 17:23:28')
187
+ result.id.class # => Fixnum
188
+ result.created_at.class # => Time
189
+
190
+ ## Clash
191
+
192
+ Clash is a Chainable Lazy Hash that allows you to easily construct
193
+ complex hashes using method notation chaining. This will allow you
194
+ to use a more action-oriented approach to building options hashes.
195
+
196
+ Essentially, a Clash is a generalized way to provide much of the same
197
+ kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
198
+ provide.
199
+
200
+ ### Example
201
+
202
+ c = Hashie::Clash.new
203
+ c.where(:abc => 'def').order(:created_at)
204
+ c # => {:where => {:abc => 'def}, :order => :created_at}
205
+
206
+ # You can also use bang notation to chain into sub-hashes,
207
+ # jumping back up the chain with _end!
208
+ c = Hashie::Clash.new
209
+ c.where!.abc('def').ghi(123)._end!.order(:created_at)
210
+ c # => {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}
211
+
212
+ # Multiple hashes are merged automatically
213
+ c = Hashie::Clash.new
214
+ c.where(:abc => 'def').where(:hgi => 123)
215
+ c # => {:where => {:abc => 'def', :hgi => 123}}
216
+
217
+
218
+ ## Note on Patches/Pull Requests
219
+
220
+ * Fork the project.
221
+ * Make your feature addition or bug fix.
222
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
223
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
224
+ * Send me a pull request. Bonus points for topic branches.
225
+
226
+ ## Authors
227
+
228
+ * Michael Bleigh
229
+
230
+ ## Copyright
231
+
232
+ Copyright (c) 2009-2011 Intridea, Inc. (http://intridea.com/). See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new do |spec|
9
+ # spec.libs << 'lib' << 'spec'
10
+ spec.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+
13
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/hashie.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../lib/hashie/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Michael Bleigh"]
5
+ gem.email = ["michael@intridea.com"]
6
+ gem.description = %q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
7
+ gem.summary = %q{Your friendly neighborhood hash toolkit.}
8
+ gem.homepage = 'https://github.com/intridea/hashie'
9
+
10
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
11
+ gem.files = `git ls-files`.split("\n")
12
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ gem.name = "hashie-pre"
14
+ gem.require_paths = ['lib']
15
+ gem.version = Hashie::VERSION
16
+
17
+ gem.add_development_dependency 'rake', '~> 0.9.2'
18
+ gem.add_development_dependency 'rspec', '~> 2.5'
19
+ gem.add_development_dependency 'guard'
20
+ gem.add_development_dependency 'guard-rspec'
21
+ gem.add_development_dependency 'growl'
22
+ end
data/lib/hashie.rb ADDED
@@ -0,0 +1,23 @@
1
+ module Hashie
2
+ autoload :Clash, 'hashie/clash'
3
+ autoload :Dash, 'hashie/dash'
4
+ autoload :Hash, 'hashie/hash'
5
+ autoload :HashExtensions, 'hashie/hash_extensions'
6
+ autoload :Mash, 'hashie/mash'
7
+ autoload :PrettyInspect, 'hashie/hash_extensions'
8
+ autoload :Trash, 'hashie/trash'
9
+
10
+ module Extensions
11
+ autoload :Coercion, 'hashie/extensions/coercion'
12
+ autoload :DeepMerge, 'hashie/extensions/deep_merge'
13
+ autoload :KeyConversion, 'hashie/extensions/key_conversion'
14
+ autoload :IndifferentAccess, 'hashie/extensions/indifferent_access'
15
+ autoload :MergeInitializer, 'hashie/extensions/merge_initializer'
16
+ autoload :MethodAccess, 'hashie/extensions/method_access'
17
+ autoload :MethodQuery, 'hashie/extensions/method_access'
18
+ autoload :MethodReader, 'hashie/extensions/method_access'
19
+ autoload :MethodWriter, 'hashie/extensions/method_access'
20
+ autoload :StringifyKeys, 'hashie/extensions/key_conversion'
21
+ autoload :SymbolizeKeys, 'hashie/extensions/key_conversion'
22
+ end
23
+ end
@@ -0,0 +1,86 @@
1
+ require 'hashie/hash'
2
+
3
+ module Hashie
4
+ #
5
+ # A Clash is a "Chainable Lazy Hash". Inspired by libraries such as Arel,
6
+ # a Clash allows you to chain together method arguments to build a
7
+ # hash, something that's especially useful if you're doing something
8
+ # like constructing a complex options hash. Here's a basic example:
9
+ #
10
+ # c = Hashie::Clash.new.conditions(:foo => 'bar').order(:created_at)
11
+ # c # => {:conditions => {:foo => 'bar'}, :order => :created_at}
12
+ #
13
+ # Clash provides another way to create sub-hashes by using bang notation.
14
+ # You can dive into a sub-hash by providing a key with a bang and dive
15
+ # back out again with the _end! method. Example:
16
+ #
17
+ # c = Hashie::Clash.new.conditions!.foo('bar').baz(123)._end!.order(:created_at)
18
+ # c # => {:conditions => {:foo => 'bar', :baz => 123}, :order => :created_at}
19
+ #
20
+ # Because the primary functionality of Clash is to build options objects,
21
+ # all keys are converted to symbols since many libraries expect symbols explicitly
22
+ # for keys.
23
+ #
24
+ class Clash < ::Hash
25
+ class ChainError < ::StandardError; end
26
+ # The parent Clash if this Clash was created via chaining.
27
+ attr_reader :_parent
28
+
29
+ # Initialize a new clash by passing in a Hash to
30
+ # convert and, optionally, the parent to which this
31
+ # Clash is chained.
32
+ def initialize(other_hash = {}, parent = nil)
33
+ @_parent = parent
34
+ other_hash.each_pair do |k, v|
35
+ self[k.to_sym] = v
36
+ end
37
+ end
38
+
39
+ # Jump back up a level if you are using bang method
40
+ # chaining. For example:
41
+ #
42
+ # c = Hashie::Clash.new.foo('bar')
43
+ # c.baz!.foo(123) # => c[:baz]
44
+ # c.baz!._end! # => c
45
+ def _end!
46
+ self._parent
47
+ end
48
+
49
+ def id(*args) #:nodoc:
50
+ method_missing(:id, *args)
51
+ end
52
+
53
+ def merge_store(key, *args) #:nodoc:
54
+ case args.length
55
+ when 1
56
+ val = args.first
57
+ val = self[key].merge(val) if self[key].is_a?(::Hash) && val.is_a?(::Hash)
58
+ else
59
+ val = args
60
+ end
61
+
62
+ self[key.to_sym] = val
63
+ self
64
+ end
65
+
66
+ def method_missing(name, *args) #:nodoc:
67
+ name = name.to_s
68
+ if name.match(/!$/) && args.empty?
69
+ key = name[0...-1].to_sym
70
+
71
+ if self[key].nil?
72
+ self[key] = Clash.new({}, self)
73
+ elsif self[key].is_a?(::Hash) && !self[key].is_a?(Clash)
74
+ self[key] = Clash.new(self[key], self)
75
+ else
76
+ raise ChainError, "Tried to chain into a non-hash key."
77
+ end
78
+
79
+ self[key]
80
+ elsif args.any?
81
+ key = name.to_sym
82
+ self.merge_store(key, *args)
83
+ end
84
+ end
85
+ end
86
+ end