hashie 0.1.0
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 +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +76 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/hashie.rb +4 -0
- data/lib/hashie/dash.rb +72 -0
- data/lib/hashie/hash.rb +8 -0
- data/lib/hashie/hash_extensions.rb +31 -0
- data/lib/hashie/mash.rb +208 -0
- data/spec/hashie/dash_spec.rb +58 -0
- data/spec/hashie/hash_spec.rb +22 -0
- data/spec/hashie/mash_spec.rb +116 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +10 -0
- metadata +83 -0
data/.document
ADDED
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.rdoc
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= Hashie
|
2
|
+
|
3
|
+
Hashie is a growing collection of tools that extend Hashes and make
|
4
|
+
them more useful.
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
Hashie is a gem and is available on Gemcutter. If you don't have Gemcutter,
|
9
|
+
install it:
|
10
|
+
|
11
|
+
gem install gemcutter
|
12
|
+
gem tumble
|
13
|
+
|
14
|
+
Then you can install Hashie:
|
15
|
+
|
16
|
+
gem install hashie
|
17
|
+
|
18
|
+
== Mash
|
19
|
+
|
20
|
+
Mash is an extended Hash that gives simple pseudo-object functionality
|
21
|
+
that can be built from hashes and easily extended. It is designed to
|
22
|
+
be used in RESTful API libraries to provide easy object-like access
|
23
|
+
to JSON and XML parsed hashes.
|
24
|
+
|
25
|
+
=== Example:
|
26
|
+
|
27
|
+
mash = Hashie::Mash.new
|
28
|
+
mash.name? # => false
|
29
|
+
mash.name # => nil
|
30
|
+
mash.name = "My Mash"
|
31
|
+
mash.name # => "My Mash"
|
32
|
+
mash.name? # => true
|
33
|
+
mash.inspect # => <Hashie::Mash name="My Mash">
|
34
|
+
|
35
|
+
mash = Mash.new
|
36
|
+
# use bang methods for multi-level assignment
|
37
|
+
mash.author!.name = "Michael Bleigh"
|
38
|
+
mash.author # => <Hashie::Mash name="Michael Bleigh">
|
39
|
+
|
40
|
+
== Dash
|
41
|
+
|
42
|
+
Dash is an extended Hash that has a discrete set of defined properties
|
43
|
+
and only those properties may be set on the hash. Additionally, you
|
44
|
+
can set defaults for each property.
|
45
|
+
|
46
|
+
=== Example:
|
47
|
+
|
48
|
+
class Person < Hashie::Dash
|
49
|
+
property :name
|
50
|
+
property :email
|
51
|
+
property :occupation, :default => 'Rubyist'
|
52
|
+
end
|
53
|
+
|
54
|
+
p = Person.new
|
55
|
+
p.name # => nil
|
56
|
+
p.occupation # => 'Rubyist'
|
57
|
+
p.email = 'abc@def.com'
|
58
|
+
p.email # => 'abc@def.com'
|
59
|
+
p['awesome'] # => NoMethodError
|
60
|
+
|
61
|
+
|
62
|
+
== Note on Patches/Pull Requests
|
63
|
+
|
64
|
+
* Fork the project.
|
65
|
+
* Make your feature addition or bug fix.
|
66
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
67
|
+
* 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)
|
68
|
+
* Send me a pull request. Bonus points for topic branches.
|
69
|
+
|
70
|
+
== Authors
|
71
|
+
|
72
|
+
* Michael Bleigh
|
73
|
+
|
74
|
+
== Copyright
|
75
|
+
|
76
|
+
Copyright (c) 2009 Intridea, Inc (http://intridea.com/). See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "hashie"
|
8
|
+
gem.summary = %Q{Your friendly neighborhood hash toolkit.}
|
9
|
+
gem.description = %Q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
|
10
|
+
gem.email = "michael@intridea.com"
|
11
|
+
gem.homepage = "http://github.com/intridea/hashie"
|
12
|
+
gem.authors = ["Michael Bleigh"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
if File.exist?('VERSION')
|
40
|
+
version = File.read('VERSION')
|
41
|
+
else
|
42
|
+
version = ""
|
43
|
+
end
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "hashie #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/hashie.rb
ADDED
data/lib/hashie/dash.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'hashie/hash'
|
2
|
+
|
3
|
+
module Hashie
|
4
|
+
# A Dash is a 'defined' or 'discrete' Hash, that is, a Hash
|
5
|
+
# that has a set of defined keys that are accessible (with
|
6
|
+
# optional defaults) and only those keys may be set or read.
|
7
|
+
#
|
8
|
+
# Dashes are useful when you need to create a very simple
|
9
|
+
# lightweight data object that needs even fewer options and
|
10
|
+
# resources than something like a DataMapper resource.
|
11
|
+
#
|
12
|
+
# It is preferrable to a Struct because of the in-class
|
13
|
+
# API for defining properties as well as per-property defaults.
|
14
|
+
class Dash < Hashie::Hash
|
15
|
+
# Defines a property on the Dash. Options are
|
16
|
+
# as follows:
|
17
|
+
#
|
18
|
+
# * <tt>:default</tt> - Specify a default value for this property,
|
19
|
+
# to be returned before a value is set on the property in a new
|
20
|
+
# Dash.
|
21
|
+
#
|
22
|
+
def self.property(property_name, options = {})
|
23
|
+
property_name = property_name.to_sym
|
24
|
+
|
25
|
+
(@properties ||= []) << property_name
|
26
|
+
(@defaults ||= {})[property_name] = options.delete(:default)
|
27
|
+
|
28
|
+
class_eval <<-RUBY
|
29
|
+
def #{property_name}
|
30
|
+
self['#{property_name}']
|
31
|
+
end
|
32
|
+
|
33
|
+
def #{property_name}=(val)
|
34
|
+
self['#{property_name}'] = val
|
35
|
+
end
|
36
|
+
RUBY
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get a String array of the currently defined
|
40
|
+
# properties on this Dash.
|
41
|
+
def self.properties
|
42
|
+
@properties.collect{|p| p.to_s}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check to see if the specified property has already been
|
46
|
+
# defined.
|
47
|
+
def self.property?(prop)
|
48
|
+
properties.include?(prop.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
# The default values that have been set for this Dash
|
52
|
+
def self.defaults
|
53
|
+
@defaults
|
54
|
+
end
|
55
|
+
|
56
|
+
# Retrieve a value from the Dash (will return the
|
57
|
+
# property's default value if it hasn't been set).
|
58
|
+
def [](property_name)
|
59
|
+
super || self.class.defaults[property_name.to_sym]
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set a value on the Dash in a Hash-like way. Only works
|
63
|
+
# on pre-existing properties.
|
64
|
+
def []=(property, value)
|
65
|
+
if self.class.property?(property)
|
66
|
+
super
|
67
|
+
else
|
68
|
+
raise NoMethodError, 'You may only set pre-defined properties.'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/hashie/hash.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Hashie
|
2
|
+
module HashExtensions
|
3
|
+
def self.included(base)
|
4
|
+
# Don't tread on existing extensions of Hash by
|
5
|
+
# adding methods that are likely to exist.
|
6
|
+
%w(stringify_keys stringify_keys!).each do |hashie_method|
|
7
|
+
base.send :alias_method, hashie_method, "hashie_#{hashie_method}" unless base.instance_methods.include?(hashie_method)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Destructively convert all of the keys of a Hash
|
12
|
+
# to their string representations.
|
13
|
+
def hashie_stringify_keys!
|
14
|
+
self.keys.each do |k|
|
15
|
+
self[k.to_s] = self.delete(k)
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
# Convert all of the keys of a Hash
|
21
|
+
# to their string representations.
|
22
|
+
def hashie_stringify_keys
|
23
|
+
self.dup.stringify_keys!
|
24
|
+
end
|
25
|
+
|
26
|
+
# Convert this hash into a Mash
|
27
|
+
def to_mash
|
28
|
+
Hashie::Mash.new(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/hashie/mash.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
module Hashie
|
2
|
+
# Mash allows you to create pseudo-objects that have method-like
|
3
|
+
# accessors for hash keys. This is useful for such implementations
|
4
|
+
# as an API-accessing library that wants to fake robust objects
|
5
|
+
# without the overhead of actually doing so. Think of it as OpenStruct
|
6
|
+
# with some additional goodies.
|
7
|
+
#
|
8
|
+
# A Mash will look at the methods you pass it and perform operations
|
9
|
+
# based on the following rules:
|
10
|
+
#
|
11
|
+
# * No punctuation: Returns the value of the hash for that key, or nil if none exists.
|
12
|
+
# * Assignment (<tt>=</tt>): Sets the attribute of the given method name.
|
13
|
+
# * Existence (<tt>?</tt>): Returns true or false depending on whether that key has been set.
|
14
|
+
# * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it as "touch" for mashes.
|
15
|
+
#
|
16
|
+
# == Basic Example
|
17
|
+
#
|
18
|
+
# mash = Mash.new
|
19
|
+
# mash.name? # => false
|
20
|
+
# mash.name = "Bob"
|
21
|
+
# mash.name # => "Bob"
|
22
|
+
# mash.name? # => true
|
23
|
+
#
|
24
|
+
# == Hash Conversion Example
|
25
|
+
#
|
26
|
+
# hash = {:a => {:b => 23, :d => {:e => "abc"}}, :f => [{:g => 44, :h => 29}, 12]}
|
27
|
+
# mash = Mash.new(hash)
|
28
|
+
# mash.a.b # => 23
|
29
|
+
# mash.a.d.e # => "abc"
|
30
|
+
# mash.f.first.g # => 44
|
31
|
+
# mash.f.last # => 12
|
32
|
+
#
|
33
|
+
# == Bang Example
|
34
|
+
#
|
35
|
+
# mash = Mash.new
|
36
|
+
# mash.author # => nil
|
37
|
+
# mash.author! # => <Mash>
|
38
|
+
#
|
39
|
+
# mash = Mash.new
|
40
|
+
# mash.author!.name = "Michael Bleigh"
|
41
|
+
# mash.author # => <Mash name="Michael Bleigh">
|
42
|
+
#
|
43
|
+
class Mash < Hashie::Hash
|
44
|
+
# If you pass in an existing hash, it will
|
45
|
+
# convert it to a Mash including recursively
|
46
|
+
# descending into arrays and hashes, converting
|
47
|
+
# them as well.
|
48
|
+
def initialize(source_hash = nil, default = nil, &blk)
|
49
|
+
deep_update(source_hash) if source_hash
|
50
|
+
super default if default
|
51
|
+
super &blk if blk
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self; alias [] new; end
|
55
|
+
|
56
|
+
def id #:nodoc:
|
57
|
+
self["id"] ? self["id"] : super
|
58
|
+
end
|
59
|
+
|
60
|
+
# Borrowed from Merb's Mash object.
|
61
|
+
#
|
62
|
+
# ==== Parameters
|
63
|
+
# key<Object>:: The default value for the mash. Defaults to nil.
|
64
|
+
#
|
65
|
+
# ==== Alternatives
|
66
|
+
# If key is a Symbol and it is a key in the mash, then the default value will
|
67
|
+
# be set to the value matching the key.
|
68
|
+
def default(key = nil)
|
69
|
+
if key.is_a?(Symbol) && key?(key.to_s)
|
70
|
+
self[key]
|
71
|
+
else
|
72
|
+
key ? super : super()
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
alias_method :regular_reader, :[]
|
77
|
+
alias_method :regular_writer, :[]=
|
78
|
+
|
79
|
+
# Retrieves an attribute set in the Mash. Will convert
|
80
|
+
# any key passed in to a string before retrieving.
|
81
|
+
def [](key)
|
82
|
+
key = convert_key(key)
|
83
|
+
regular_reader(key)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets an attribute in the Mash. Key will be converted to
|
87
|
+
# a string before it is set, and Hashes will be converted
|
88
|
+
# into Mashes for nesting purposes.
|
89
|
+
def []=(key,value) #:nodoc:
|
90
|
+
key = convert_key(key)
|
91
|
+
regular_writer(key, convert_value(value))
|
92
|
+
end
|
93
|
+
|
94
|
+
# This is the bang method reader, it will return a new Mash
|
95
|
+
# if there isn't a value already assigned to the key requested.
|
96
|
+
def initializing_reader(key)
|
97
|
+
self[key] = Hashie::Mash.new unless key?(key)
|
98
|
+
self[key]
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :regular_dup, :dup
|
102
|
+
# Duplicates the current mash as a new mash.
|
103
|
+
def dup
|
104
|
+
Mash.new(self, self.default)
|
105
|
+
end
|
106
|
+
|
107
|
+
alias_method :picky_key?, :key?
|
108
|
+
def key?(key)
|
109
|
+
picky_key?(convert_key(key))
|
110
|
+
end
|
111
|
+
|
112
|
+
alias_method :regular_inspect, :inspect
|
113
|
+
# Prints out a pretty object-like string of the
|
114
|
+
# defined attributes.
|
115
|
+
def inspect
|
116
|
+
ret = "<#{self.class.to_s}"
|
117
|
+
keys.sort.each do |key|
|
118
|
+
ret << " #{key}=#{self[key].inspect}"
|
119
|
+
end
|
120
|
+
ret << ">"
|
121
|
+
ret
|
122
|
+
end
|
123
|
+
alias_method :to_s, :inspect
|
124
|
+
|
125
|
+
# Performs a deep_update on a duplicate of the
|
126
|
+
# current mash.
|
127
|
+
def deep_merge(other_hash)
|
128
|
+
dup.deep_merge!(other_hash)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Recursively merges this mash with the passed
|
132
|
+
# in hash, merging each hash in the hierarchy.
|
133
|
+
def deep_update(other_hash)
|
134
|
+
other_hash = Hashie::Hash[other_hash].stringify_keys!
|
135
|
+
|
136
|
+
other_hash.each_pair do |k,v|
|
137
|
+
k = convert_key(k)
|
138
|
+
self[k] = Hashie::Mash.new(self[k]).to_mash if self[k].is_a?(Hash) unless self[k].is_a?(Hashie::Mash)
|
139
|
+
if self[k].is_a?(Hashie::Mash) && other_hash[k].is_a?(Hash)
|
140
|
+
self[k] = self[k].deep_merge(other_hash[k])
|
141
|
+
else
|
142
|
+
self[k] = convert_value(other_hash[k],true)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
self
|
147
|
+
end
|
148
|
+
alias_method :deep_merge!, :deep_update
|
149
|
+
|
150
|
+
# ==== Parameters
|
151
|
+
# other_hash<Hash>::
|
152
|
+
# A hash to update values in the mash with. Keys will be
|
153
|
+
# stringified and Hashes will be converted to Mashes.
|
154
|
+
#
|
155
|
+
# ==== Returns
|
156
|
+
# Mash:: The updated mash.
|
157
|
+
def update(other_hash)
|
158
|
+
other_hash.each_pair do |key, value|
|
159
|
+
if respond_to?(convert_key(key) + "=")
|
160
|
+
self.send(convert_key(key) + "=", convert_value(value))
|
161
|
+
else
|
162
|
+
regular_writer(convert_key(key), convert_value(value))
|
163
|
+
end
|
164
|
+
end
|
165
|
+
self
|
166
|
+
end
|
167
|
+
alias_method :merge!, :update
|
168
|
+
|
169
|
+
# Converts a mash back to a hash (with stringified keys)
|
170
|
+
def to_hash
|
171
|
+
Hash.new(default).merge(self)
|
172
|
+
end
|
173
|
+
|
174
|
+
def method_missing(method_name, *args) #:nodoc:
|
175
|
+
if (match = method_name.to_s.match(/(.*)=$/)) && args.size == 1
|
176
|
+
self[match[1]] = args.first
|
177
|
+
elsif (match = method_name.to_s.match(/(.*)\?$/)) && args.size == 0
|
178
|
+
key?(match[1])
|
179
|
+
elsif (match = method_name.to_s.match(/(.*)!$/)) && args.size == 0
|
180
|
+
initializing_reader(match[1])
|
181
|
+
elsif key?(method_name)
|
182
|
+
self[method_name]
|
183
|
+
elsif match = method_name.to_s.match(/^([a-z][a-z0-9A-Z_]+)$/)
|
184
|
+
default(method_name)
|
185
|
+
else
|
186
|
+
super
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
protected
|
191
|
+
|
192
|
+
def convert_key(key) #:nodoc:
|
193
|
+
key.to_s
|
194
|
+
end
|
195
|
+
|
196
|
+
def convert_value(val, duping=false) #:nodoc:
|
197
|
+
case val
|
198
|
+
when ::Hash
|
199
|
+
val = val.dup if duping
|
200
|
+
Hashie::Mash.new(val)
|
201
|
+
when Array
|
202
|
+
val.collect{ |e| convert_value(e) }
|
203
|
+
else
|
204
|
+
val
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class DashTest < Hashie::Dash
|
4
|
+
property :first_name
|
5
|
+
property :email
|
6
|
+
property :count, :default => 0
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Hashie::Dash do
|
10
|
+
it 'should be a subclass of Hashie::Hash' do
|
11
|
+
(Hashie::Dash < Hash).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ' creating properties' do
|
15
|
+
it 'should add the property to the list' do
|
16
|
+
DashTest.property :not_an_att
|
17
|
+
DashTest.properties.include?('not_an_att').should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should create a method for reading the property' do
|
21
|
+
DashTest.new.respond_to?(:first_name).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should create a method for writing the property' do
|
25
|
+
DashTest.new.respond_to?(:first_name=).should be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ' writing to properties' do
|
30
|
+
before do
|
31
|
+
@dash = DashTest.new
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should not be able to write to a non-existent property using []=' do
|
35
|
+
lambda{@dash['abc'] = 123}.should raise_error(NoMethodError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should be able to write to an existing property using []=' do
|
39
|
+
lambda{@dash['first_name'] = 'Bob'}.should_not raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should be able to read/write to an existing property using a method call' do
|
43
|
+
@dash.first_name = 'Franklin'
|
44
|
+
@dash.first_name.should == 'Franklin'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe ' defaults' do
|
49
|
+
before do
|
50
|
+
@dash = DashTest.new
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should return the default value for defaulted' do
|
54
|
+
DashTest.property :defaulted, :default => 'abc'
|
55
|
+
DashTest.new.defaulted.should == 'abc'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
it "should be convertible to a Hashie::Mash" do
|
5
|
+
mash = Hashie::Hash[:some => "hash"].to_mash
|
6
|
+
mash.is_a?(Hashie::Mash).should be_true
|
7
|
+
mash.some.should == "hash"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "#stringify_keys! should turn all keys into strings" do
|
11
|
+
hash = Hashie::Hash[:a => "hey", 123 => "bob"]
|
12
|
+
hash.stringify_keys!
|
13
|
+
hash.should == Hashie::Hash["a" => "hey", "123" => "bob"]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "#stringify_keys should return a hash with stringified keys" do
|
17
|
+
hash = Hashie::Hash[:a => "hey", 123 => "bob"]
|
18
|
+
stringified_hash = hash.stringify_keys
|
19
|
+
hash.should == Hashie::Hash[:a => "hey", 123 => "bob"]
|
20
|
+
stringified_hash.should == Hashie::Hash["a" => "hey", "123" => "bob"]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Hashie::Mash do
|
4
|
+
before(:each) do
|
5
|
+
@mash = Hashie::Mash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should inherit from hash" do
|
9
|
+
@mash.is_a?(Hash).should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be able to set hash values through method= calls" do
|
13
|
+
@mash.test = "abc"
|
14
|
+
@mash["test"].should == "abc"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to retrieve set values through method calls" do
|
18
|
+
@mash["test"] = "abc"
|
19
|
+
@mash.test.should == "abc"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should test for already set values when passed a ? method" do
|
23
|
+
@mash.test?.should be_false
|
24
|
+
@mash.test = "abc"
|
25
|
+
@mash.test?.should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should make all [] and []= into strings for consistency" do
|
29
|
+
@mash["abc"] = 123
|
30
|
+
@mash.key?('abc').should be_true
|
31
|
+
@mash["abc"].should == 123
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have a to_s that is identical to its inspect" do
|
35
|
+
@mash.abc = 123
|
36
|
+
@mash.to_s.should == @mash.inspect
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return nil instead of raising an error for attribute-esque method calls" do
|
40
|
+
@mash.abc.should be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return a Hashie::Mash when passed a bang method to a non-existenct key" do
|
44
|
+
@mash.abc!.is_a?(Hashie::Mash).should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return the existing value when passed a bang method for an existing key" do
|
48
|
+
@mash.name = "Bob"
|
49
|
+
@mash.name!.should == "Bob"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "#initializing_reader should return a Hashie::Mash when passed a non-existent key" do
|
53
|
+
@mash.initializing_reader(:abc).is_a?(Hashie::Mash).should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should allow for multi-level assignment through bang methods" do
|
57
|
+
@mash.author!.name = "Michael Bleigh"
|
58
|
+
@mash.author.should == Hashie::Mash.new(:name => "Michael Bleigh")
|
59
|
+
@mash.author!.website!.url = "http://www.mbleigh.com/"
|
60
|
+
@mash.author.website.should == Hashie::Mash.new(:url => "http://www.mbleigh.com/")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "#deep_update should recursively Hashie::Mash Hashie::Mashes and hashes together" do
|
64
|
+
@mash.first_name = "Michael"
|
65
|
+
@mash.last_name = "Bleigh"
|
66
|
+
@mash.details = Hashie::Hash[:email => "michael@asf.com"].to_mash
|
67
|
+
@mash.deep_update({:details => {:email => "michael@intridea.com"}})
|
68
|
+
@mash.details.email.should == "michael@intridea.com"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should convert hash assignments into Hashie::Mashes" do
|
72
|
+
@mash.details = {:email => 'randy@asf.com', :address => {:state => 'TX'} }
|
73
|
+
@mash.details.email.should == 'randy@asf.com'
|
74
|
+
@mash.details.address.state.should == 'TX'
|
75
|
+
end
|
76
|
+
|
77
|
+
context "#initialize" do
|
78
|
+
it "should convert an existing hash to a Hashie::Mash" do
|
79
|
+
converted = Hashie::Mash.new({:abc => 123, :name => "Bob"})
|
80
|
+
converted.abc.should == 123
|
81
|
+
converted.name.should == "Bob"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should convert hashes recursively into Hashie::Mashes" do
|
85
|
+
converted = Hashie::Mash.new({:a => {:b => 1, :c => {:d => 23}}})
|
86
|
+
converted.a.is_a?(Hashie::Mash).should be_true
|
87
|
+
converted.a.b.should == 1
|
88
|
+
converted.a.c.d.should == 23
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should convert hashes in arrays into Hashie::Mashes" do
|
92
|
+
converted = Hashie::Mash.new({:a => [{:b => 12}, 23]})
|
93
|
+
converted.a.first.b.should == 12
|
94
|
+
converted.a.last.should == 23
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should convert an existing Hashie::Mash into a Hashie::Mash" do
|
98
|
+
initial = Hashie::Mash.new(:name => 'randy', :address => {:state => 'TX'})
|
99
|
+
copy = Hashie::Mash.new(initial)
|
100
|
+
initial.name.should == copy.name
|
101
|
+
initial.object_id.should_not == copy.object_id
|
102
|
+
copy.address.state.should == 'TX'
|
103
|
+
copy.address.state = 'MI'
|
104
|
+
initial.address.state.should == 'TX'
|
105
|
+
copy.address.object_id.should_not == initial.address.object_id
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should accept a default block" do
|
109
|
+
initial = Hashie::Mash.new { |h,i| h[i] = []}
|
110
|
+
initial.default_proc.should_not be_nil
|
111
|
+
initial.default.should be_nil
|
112
|
+
initial.test.should == []
|
113
|
+
initial.test?.should be_true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hashie
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Bleigh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-12 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).
|
26
|
+
email: michael@intridea.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- lib/hashie.rb
|
42
|
+
- lib/hashie/dash.rb
|
43
|
+
- lib/hashie/hash.rb
|
44
|
+
- lib/hashie/hash_extensions.rb
|
45
|
+
- lib/hashie/mash.rb
|
46
|
+
- spec/hashie/dash_spec.rb
|
47
|
+
- spec/hashie/hash_spec.rb
|
48
|
+
- spec/hashie/mash_spec.rb
|
49
|
+
- spec/spec.opts
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://github.com/intridea/hashie
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --charset=UTF-8
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.5
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Your friendly neighborhood hash toolkit.
|
79
|
+
test_files:
|
80
|
+
- spec/hashie/dash_spec.rb
|
81
|
+
- spec/hashie/hash_spec.rb
|
82
|
+
- spec/hashie/mash_spec.rb
|
83
|
+
- spec/spec_helper.rb
|