hashie 0.1.8 → 0.2.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.
@@ -4,14 +4,8 @@ Hashie is a growing collection of tools that extend Hashes and make
4
4
  them more useful.
5
5
 
6
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
7
 
14
- Then you can install Hashie:
8
+ Hashie is available as a RubyGem:
15
9
 
16
10
  gem install hashie
17
11
 
@@ -62,7 +56,33 @@ can set defaults for each property.
62
56
  p = Person.new(:name => "Bob")
63
57
  p.name # => 'Bob'
64
58
  p.occupation # => 'Rubyist'
65
-
59
+
60
+ == Clash
61
+
62
+ Clash is a Chainable Lazy Hash that allows you to easily construct
63
+ complex hashes using method notation chaining. This will allow you
64
+ to use a more action-oriented approach to building options hashes.
65
+
66
+ Essentially, a Clash is a generalized way to provide much of the same
67
+ kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
68
+ provide.
69
+
70
+ === Example
71
+
72
+ c = Hashie::Clash.new
73
+ c.where(:abc => 'def').order(:created_at)
74
+ c # => {:where => {:abc => 'def}, :order => :created_at}
75
+
76
+ # You can also use bang notation to chain into sub-hashes,
77
+ # jumping back up the chain with _end!
78
+ c = Hashie::Clash.new
79
+ c.where!.abc('def').ghi(123)._end!.order(:created_at)
80
+ c # => {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}
81
+
82
+ # Multiple hashes are merged automatically
83
+ c = Hashie::Clash.new
84
+ c.where(:abc => 'def').where(:hgi => 123)
85
+ c # => {:where => {:abc => 'def', :hgi => 123}}
66
86
 
67
87
  == Note on Patches/Pull Requests
68
88
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hashie}
8
- s.version = "0.1.8"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Bleigh"]
12
- s.date = %q{2010-01-14}
12
+ s.date = %q{2010-03-05}
13
13
  s.description = %q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
14
14
  s.email = %q{michael@intridea.com}
15
15
  s.extra_rdoc_files = [
@@ -25,10 +25,12 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "hashie.gemspec",
27
27
  "lib/hashie.rb",
28
+ "lib/hashie/clash.rb",
28
29
  "lib/hashie/dash.rb",
29
30
  "lib/hashie/hash.rb",
30
31
  "lib/hashie/hash_extensions.rb",
31
32
  "lib/hashie/mash.rb",
33
+ "spec/hashie/clash_spec.rb",
32
34
  "spec/hashie/dash_spec.rb",
33
35
  "spec/hashie/hash_spec.rb",
34
36
  "spec/hashie/mash_spec.rb",
@@ -38,10 +40,11 @@ Gem::Specification.new do |s|
38
40
  s.homepage = %q{http://github.com/intridea/hashie}
39
41
  s.rdoc_options = ["--charset=UTF-8"]
40
42
  s.require_paths = ["lib"]
41
- s.rubygems_version = %q{1.3.5}
43
+ s.rubygems_version = %q{1.3.6}
42
44
  s.summary = %q{Your friendly neighborhood hash toolkit.}
43
45
  s.test_files = [
44
- "spec/hashie/dash_spec.rb",
46
+ "spec/hashie/clash_spec.rb",
47
+ "spec/hashie/dash_spec.rb",
45
48
  "spec/hashie/hash_spec.rb",
46
49
  "spec/hashie/mash_spec.rb",
47
50
  "spec/spec_helper.rb"
@@ -1,4 +1,5 @@
1
1
  require 'hashie/hash_extensions'
2
2
  require 'hashie/hash'
3
3
  require 'hashie/mash'
4
- require 'hashie/dash'
4
+ require 'hashie/dash'
5
+ require 'hashie/clash'
@@ -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
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Hashie::Clash do
4
+ before do
5
+ @c = Hashie::Clash.new
6
+ end
7
+
8
+ it 'should be able to set an attribute via method_missing' do
9
+ @c.foo('bar')
10
+ @c[:foo].should == 'bar'
11
+ end
12
+
13
+ it 'should be able to set multiple attributes' do
14
+ @c.foo('bar').baz('wok')
15
+ @c.should == {:foo => 'bar', :baz => 'wok'}
16
+ end
17
+
18
+ it 'should convert multiple arguments into an array' do
19
+ @c.foo(1, 2, 3)
20
+ @c[:foo].should == [1,2,3]
21
+ end
22
+
23
+ it 'should be able to use bang notation to create a new Clash on a key' do
24
+ @c.foo!
25
+ @c[:foo].should be_kind_of(Hashie::Clash)
26
+ end
27
+
28
+ it 'should be able to chain onto the new Clash when using bang notation' do
29
+ @c.foo!.bar('abc').baz(123)
30
+ @c.should == {:foo => {:bar => 'abc', :baz => 123}}
31
+ end
32
+
33
+ it 'should be able to jump back up to the parent in the chain with #_end!' do
34
+ @c.foo!.bar('abc')._end!.baz(123)
35
+ @c.should == {:foo => {:bar => 'abc'}, :baz => 123}
36
+ end
37
+
38
+ it 'should merge rather than replace existing keys' do
39
+ @c.where(:abc => 'def').where(:hgi => 123)
40
+ @c.should == {:where => {:abc => 'def', :hgi => 123}}
41
+ end
42
+ end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Michael Bleigh
@@ -9,19 +14,21 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-14 00:00:00 -05:00
17
+ date: 2010-03-05 00:00:00 -05:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
23
29
  version: "0"
24
- version:
30
+ type: :development
31
+ version_requirements: *id001
25
32
  description: Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).
26
33
  email: michael@intridea.com
27
34
  executables: []
@@ -40,10 +47,12 @@ files:
40
47
  - VERSION
41
48
  - hashie.gemspec
42
49
  - lib/hashie.rb
50
+ - lib/hashie/clash.rb
43
51
  - lib/hashie/dash.rb
44
52
  - lib/hashie/hash.rb
45
53
  - lib/hashie/hash_extensions.rb
46
54
  - lib/hashie/mash.rb
55
+ - spec/hashie/clash_spec.rb
47
56
  - spec/hashie/dash_spec.rb
48
57
  - spec/hashie/hash_spec.rb
49
58
  - spec/hashie/mash_spec.rb
@@ -62,22 +71,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
62
71
  requirements:
63
72
  - - ">="
64
73
  - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
65
76
  version: "0"
66
- version:
67
77
  required_rubygems_version: !ruby/object:Gem::Requirement
68
78
  requirements:
69
79
  - - ">="
70
80
  - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
71
83
  version: "0"
72
- version:
73
84
  requirements: []
74
85
 
75
86
  rubyforge_project:
76
- rubygems_version: 1.3.5
87
+ rubygems_version: 1.3.6
77
88
  signing_key:
78
89
  specification_version: 3
79
90
  summary: Your friendly neighborhood hash toolkit.
80
91
  test_files:
92
+ - spec/hashie/clash_spec.rb
81
93
  - spec/hashie/dash_spec.rb
82
94
  - spec/hashie/hash_spec.rb
83
95
  - spec/hashie/mash_spec.rb