hashie-pre 2.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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