attribute-kit 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  group :development do
4
+ gem 'yajl-ruby', '>= 0.8.2', :require => 'yajl/json_gem'
4
5
  gem "rspec", "~> 2.3.0"
5
6
  gem "bundler", "~> 1.0.0"
6
7
  gem "jeweler", "~> 1.6.4"
@@ -18,6 +18,7 @@ GEM
18
18
  rspec-expectations (2.3.0)
19
19
  diff-lcs (~> 1.1.2)
20
20
  rspec-mocks (2.3.0)
21
+ yajl-ruby (0.8.2)
21
22
  yard (0.7.2)
22
23
 
23
24
  PLATFORMS
@@ -29,4 +30,5 @@ DEPENDENCIES
29
30
  rcov
30
31
  rdiscount
31
32
  rspec (~> 2.3.0)
33
+ yajl-ruby (>= 0.8.2)
32
34
  yard
@@ -2,8 +2,101 @@
2
2
 
3
3
  Tools for attribute tracking like Hashes with dirty tracking and events, for building hybrid models and generally going beyond what's provided by your local ORM/DRM, while allowing you to expand what you can do with them, live without them, or roll your own
4
4
 
5
+ ## Rationale
6
+
7
+ ORM and DRM frameworks implement many of the same concepts that this kit makes available, but they don't generally expose them
8
+ as smaller pieces of functionality that you can consume and mix in as you please. It is also difficult to get more ORMs to
9
+ 'play nice' with columns that are really schemaless hashes, because they just aren't meant to handle such things. While DRMs
10
+ are generally designed to work with schemaless data, there are times when you need to have both behaviors.
11
+
12
+ The idea behind building AttributeKit was to make these concepts available in an ad-hoc format, so that classes could either
13
+ inherit or mix in the behaviors that they want and/or need, without the overhead of the pieces they don't want or need. This
14
+ all stemmed from a side project that had a need for exactly that...ORM/DRM-like behavior, without the extra weight of actually
15
+ using one of the ORMs or DRMs on the market and then extending them to handle both types of data, in two separate data stores.
16
+
17
+ ## Basic usage
18
+
19
+ attributes = AttributeKit::AttributeHash.new #=> {}
20
+
21
+ attributes.empty? #=> true
22
+ attributes.dirty? #=> false
23
+ attributes[:foo] = 'bar' #=> 'bar'
24
+ attributes.dirty? #=> true
25
+ attributes.dirty_keys #=> [:foo]
26
+ attributes #=> {:foo=>"bar"}
27
+
28
+ attributes[:bar] = 5 #=> 5
29
+ attributes #=> {:foo=>"bar", :bar=>5}
30
+ attributes.dirty_keys #=> [:foo, :bar]
31
+ attributes.deleted_keys #=> []
32
+
33
+ attributes.delete(:foo) #=> "bar"
34
+ attributes.dirty_keys #=> [:bar, :foo]
35
+ attributes.deleted_keys #=> [:foo]
36
+
37
+ attributes.clean_attributes { |dirty_attrs| # Deleted: foo Nil value: true
38
+ dirty_attrs.each_pair do |k,v| # Changed: bar New value: 5
39
+ case v[0]
40
+ when :changed #=> {:foo=>[:deleted, nil], :bar=>[:changed, 5]}
41
+ puts "Changed: #{k} New value: #{v[1]}"
42
+ when :deleted # NOTE: The lack of a return value in this block
43
+ puts "Deleted: #{k} Nil value: #{v[1].nil?}" # means that dirty_attrs was returned by both
44
+ end # the block and the method itself. You may
45
+ end # want to write a block to return true if it
46
+ } # succeeds, and the dirty_attrs hash if it
47
+ # fails, so you can pass the hash to a
48
+ # method that can retry later.
49
+
50
+ ## Serializing and deserializing a Hash with JSON
51
+
52
+ class JHash < Hash
53
+ include AttributeKit::JSONSerializableHash
54
+ end
55
+
56
+ attr_hash = JHash.new #=> {}
57
+ attr_hash[:foo] = 'bar' #=> 'bar'
58
+ attr_hash[:bar] = 5 #=> 5
59
+ attr_hash #=> {:foo=>"bar", :bar=>5}
60
+
61
+ j = attr_hash.to_json #=> "{\"foo\":\"bar\",\"bar\":5}"
62
+ new_hash = JHash.new #=> {}
63
+ new_hash.from_json(j) #=> {:foo=>"bar", :bar=>5}
64
+ new_hash #=> {:foo=>"bar", :bar=>5}
65
+ new_hash.clear #=> {}
66
+
67
+ f = attr_hash.get_json(:foo) #=> "{\"foo\":\"bar\"}"
68
+ new_hash[:bar] = 5 #=> 5
69
+ new_hash.store_json(f) #=> {:bar=>5, :foo=>"bar"}
70
+ new_hash #=> {:bar=>5, :foo=>"bar"}
71
+
72
+ ## Serializing and deserializing an AttributeHash with JSON
73
+
74
+ class MyHash < AttributeKit::AttributeHash
75
+ include AttributeKit::JSONSerializableHash
76
+ end
77
+
78
+ attr_hash = MyHash.new #=> {}
79
+ attr_hash.empty? #=> true
80
+ attr_hash.dirty? #=> false
81
+ attr_hash[:foo] = 'bar' #=> 'bar'
82
+ attr_hash.dirty? #=> true
83
+ attr_hash.dirty_keys #=> [:foo]
84
+ attr_hash[:bar] = 5 #=> 5
85
+ attr_hash #=> {:foo=>"bar", :bar=>5}
86
+
87
+ j = attr_hash.to_json #=> "{\"foo\":\"bar\",\"bar\":5}"
88
+ new_hash = MyHash.new #=> {}
89
+ new_hash.from_json(j) #=> {:foo=>"bar", :bar=>5}
90
+ new_hash #=> {:foo=>"bar", :bar=>5}
91
+ new_hash.clear #=> {}
92
+
93
+ f = attr_hash.get_json(:foo) #=> "{\"foo\":\"bar\"}"
94
+ new_hash[:bar] = 5 #=> 5
95
+ new_hash.store_json(f) #=> {:bar=>5, :foo=>"bar"}
96
+ new_hash #=> {:bar=>5, :foo=>"bar"}
97
+
5
98
  ## Contributing to attribute-kit
6
-
99
+
7
100
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
101
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
102
  * Fork the project
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.0
@@ -1 +1,2 @@
1
1
  require 'attribute-kit/attribute_hash'
2
+ require 'attribute-kit/json_serializable_hash'
@@ -13,6 +13,39 @@
13
13
  module AttributeKit
14
14
 
15
15
  # AttributeHash inherits from and extends Hash, to provide tracking of attribute status (changed/deleted keys).
16
+ #
17
+ # @example Basic usage
18
+ # attributes = AttributeKit::AttributeHash.new #=> {}
19
+ #
20
+ # attributes.empty? #=> true
21
+ # attributes.dirty? #=> false
22
+ # attributes[:foo] = 'bar' #=> 'bar'
23
+ # attributes.dirty? #=> true
24
+ # attributes.dirty_keys #=> [:foo]
25
+ # attributes #=> {:foo=>"bar"}
26
+ #
27
+ # attributes[:bar] = 5 #=> 5
28
+ # attributes #=> {:foo=>"bar", :bar=>5}
29
+ # attributes.dirty_keys #=> [:foo, :bar]
30
+ # attributes.deleted_keys #=> []
31
+ #
32
+ # attributes.delete(:foo) #=> "bar"
33
+ # attributes.dirty_keys #=> [:bar, :foo]
34
+ # attributes.deleted_keys #=> [:foo]
35
+ #
36
+ # attributes.clean_attributes { |dirty_attrs| # Deleted: foo Nil value: true
37
+ # dirty_attrs.each_pair do |k,v| # Changed: bar New value: 5
38
+ # case v[0]
39
+ # when :changed #=> {:foo=>[:deleted, nil], :bar=>[:changed, 5]}
40
+ # puts "Changed: #{k} New value: #{v[1]}"
41
+ # when :deleted # NOTE: The lack of a return value in this block
42
+ # puts "Deleted: #{k} Nil value: #{v[1].nil?}" # means that dirty_attrs was returned by both
43
+ # end # the block and the method itself. You may
44
+ # end # want to write a block to return true if it
45
+ # } # succeeds, and the dirty_attrs hash if it
46
+ # # fails, so you can pass the hash to a
47
+ # # method that can retry later.
48
+ #
16
49
  class AttributeHash < Hash
17
50
 
18
51
  # @visibility private
@@ -32,6 +65,7 @@ module AttributeKit
32
65
  private_class_method :cond_deletion_method
33
66
 
34
67
  # Creates a new instance, using identical syntax to Hash
68
+ # @return [AttributeHash] new instance
35
69
  # @see Hash#new
36
70
  def initialize(*args)
37
71
  super(*args)
@@ -155,7 +189,8 @@ module AttributeKit
155
189
  [k,v]
156
190
  end
157
191
 
158
- # Clear all contents of the object.
192
+ # Clear all contents of the object and mark it as dirty. An array of all removed keys is available via #deleted_keys.
193
+ # @return [AttributeHash] an empty AttributeHash
159
194
  # @see Hash#clear
160
195
  def clear
161
196
  @deleted_keys += self.keys
@@ -187,6 +222,13 @@ module AttributeKit
187
222
  # that have changed since the object was last marked clean. Marks the object as clean when it compiles
188
223
  # the list of keys that have been modified.
189
224
  # @param [Block] block to execute with hash of modified keys, actions, and values
225
+ # @yield [dirty_attrs] block is executed once, with a hash of dirty attributes
226
+ # @yieldparam [Hash] dirty_attrs the hash of changed/deleted attributes with the modified key as the key and a value
227
+ # of an array in the format: [ACTION, VALUE] where ACTION is either :changed or :deleted, and VALUE is either the
228
+ # new value or nil if the attribute is deleted. A nil value does NOT mean the attribute is deleted if the ACTION
229
+ # is :changed, it means the value was actually set to nil
230
+ # @yieldreturn [Object] any value the block returns bubbles up, otherwise
231
+ # @return [Object] the return value of the block is returned
190
232
  def clean_attributes(&block)
191
233
  if !@dirty_keys.empty?
192
234
  dirty_attrs = {}
@@ -0,0 +1,107 @@
1
+ begin
2
+ require 'yajl/json_gem'
3
+ rescue LoadError
4
+ begin
5
+ require 'json'
6
+ rescue LoadError
7
+ require 'json_pure'
8
+ end
9
+ end
10
+
11
+ module AttributeKit
12
+
13
+ # JSONSerializableHash adds a set of methods to manage serialization and deserialization of hashes and Hash decendants
14
+ # in a consistent manner. By default, the methods symbolize the keys when they are deserialized, which greatly
15
+ # improves performance and also provides consistency in how keys appear both in JSON and in the hash.
16
+ #
17
+ # @example Serializing and deserializing a Hash with JSON
18
+ #
19
+ # class JHash < Hash
20
+ # include AttributeKit::JSONSerializableHash
21
+ # end
22
+ #
23
+ # attr_hash = JHash.new #=> {}
24
+ # attr_hash[:foo] = 'bar' #=> 'bar'
25
+ # attr_hash[:bar] = 5 #=> 5
26
+ # attr_hash #=> {:foo=>"bar", :bar=>5}
27
+ #
28
+ # j = attr_hash.to_json #=> "{\"foo\":\"bar\",\"bar\":5}"
29
+ # new_hash = JHash.new #=> {}
30
+ # new_hash.from_json(j) #=> {:foo=>"bar", :bar=>5}
31
+ # new_hash #=> {:foo=>"bar", :bar=>5}
32
+ # new_hash.clear #=> {}
33
+ #
34
+ # f = attr_hash.get_json(:foo) #=> "{\"foo\":\"bar\"}"
35
+ # new_hash[:bar] = 5 #=> 5
36
+ # new_hash.store_json(f) #=> {:bar=>5, :foo=>"bar"}
37
+ # new_hash #=> {:bar=>5, :foo=>"bar"}
38
+ #
39
+ #
40
+ # @example Serializing and deserializing an AttributeHash with JSON
41
+ #
42
+ # class MyHash < AttributeKit::AttributeHash
43
+ # include AttributeKit::JSONSerializableHash
44
+ # end
45
+ #
46
+ # attr_hash = MyHash.new #=> {}
47
+ # attr_hash.empty? #=> true
48
+ # attr_hash.dirty? #=> false
49
+ # attr_hash[:foo] = 'bar' #=> 'bar'
50
+ # attr_hash.dirty? #=> true
51
+ # attr_hash.dirty_keys #=> [:foo]
52
+ # attr_hash[:bar] = 5 #=> 5
53
+ # attr_hash #=> {:foo=>"bar", :bar=>5}
54
+ #
55
+ # j = attr_hash.to_json #=> "{\"foo\":\"bar\",\"bar\":5}"
56
+ # new_hash = MyHash.new #=> {}
57
+ # new_hash.from_json(j) #=> {:foo=>"bar", :bar=>5}
58
+ # new_hash #=> {:foo=>"bar", :bar=>5}
59
+ # new_hash.clear #=> {}
60
+ #
61
+ # f = attr_hash.get_json(:foo) #=> "{\"foo\":\"bar\"}"
62
+ # new_hash[:bar] = 5 #=> 5
63
+ # new_hash.store_json(f) #=> {:bar=>5, :foo=>"bar"}
64
+ # new_hash #=> {:bar=>5, :foo=>"bar"}
65
+ #
66
+ module JSONSerializableHash
67
+
68
+ # Serializes the entire hash contents into a JSON string.
69
+ # @param [Hash] opts A hash of options to be passed to the JSON generator, empty by default
70
+ # @return [String] A JSON encoded string describing the contents of the hash
71
+ def to_json(opts = {})
72
+ JSON.generate(self, opts)
73
+ end
74
+
75
+ # Deserializes hash contents from a JSON string, replacing the contents of the hash if they already exist
76
+ # @param [String] json A JSON formatted string to be parsed and assigned as the contents of the hash
77
+ # @param [Hash] opts A hash of options to be passed to the JSON generator, :symbolize_keys => true is set by default
78
+ # @return [Hash] The new contents of the hash
79
+ def from_json(json, opts = {})
80
+ defaults = {
81
+ :symbolize_keys => true
82
+ }
83
+ opts.merge!(defaults){ |key, param, default| param }
84
+ self.replace(JSON.parse(json, opts))
85
+ end
86
+
87
+ # Serializes a single key-value pair from the hash contents into a JSON string.
88
+ # @param [Symbol] key The key for the key-value pair to retrieve and encode
89
+ # @param [Hash] opts A hash of options to be passed to the JSON generator, empty by default
90
+ # @return [String] A JSON encoded string describing the key-value pair
91
+ def get_json(key, opts = {})
92
+ JSON.generate({key => self[key]}, opts)
93
+ end
94
+
95
+ # Deserializes hash contents from a JSON string, merging the contents with any contents of the hash that already exist
96
+ # @param [String] json A JSON formatted string to be parsed and update the contents of the hash with
97
+ # @param [Hash] opts A hash of options to be passed to the JSON generator, :symbolize_keys => true is set by default
98
+ # @return [Hash] The new contents of the hash
99
+ def store_json(json, opts = {})
100
+ defaults = {
101
+ :symbolize_keys => true
102
+ }
103
+ opts.merge!(defaults){ |key, param, default| param }
104
+ self.update(JSON.parse(json, opts))
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ class JSONSerializableHashTestHash < Hash
4
+ include AttributeKit::JSONSerializableHash
5
+ end
6
+
7
+ describe "AttributeKit" do
8
+ context '::JSONSerializableHash' do
9
+ it 'should load' do
10
+ defined?(AttributeKit::JSONSerializableHash).should == 'constant'
11
+ end
12
+
13
+ before(:each) do
14
+ @hash = JSONSerializableHashTestHash.new
15
+ @hash[:a] = 'a'
16
+ @hash[:b] = 2
17
+ @hash[:c] = nil
18
+ @hash[:float] = 3.14
19
+ @hash[:integer] = 5.to_i
20
+ end
21
+
22
+ context '#to_json' do
23
+ it 'should serialize the contents of the hash to JSON' do
24
+ json = @hash.to_json
25
+ json.should == '{"a":"a","b":2,"c":null,"float":3.14,"integer":5}'
26
+ end
27
+ end
28
+
29
+ context '#from_json' do
30
+ before(:each) do
31
+ @new_hash = JSONSerializableHashTestHash.new
32
+ @new_hash.from_json('{"a":"a","b":2,"c":null,"float":3.14,"integer":5}')
33
+ end
34
+
35
+ it 'should use symbols for the keys instead of strings or other objects' do
36
+ @new_hash.has_key?(:a).should be_true
37
+ @new_hash.has_key?('a').should be_false
38
+ end
39
+
40
+ it 'should deserialize JSON into the correct contents of the hash' do
41
+ @new_hash.length.should == 5
42
+ @new_hash[:a].should == 'a'
43
+ @new_hash[:b].should == 2
44
+ @new_hash[:c].should be_nil
45
+ @new_hash[:float].should == 3.14
46
+ @new_hash[:integer].should == 5
47
+ end
48
+ end
49
+
50
+ context '#get_json' do
51
+ it 'should retrieve a key-value pair with a String value and JSON encode it' do
52
+ json = @hash.get_json(:a)
53
+ json.should == '{"a":"a"}'
54
+ end
55
+
56
+ it 'should retrieve a key-value pair with a Fixnum value and JSON encode it' do
57
+ json = @hash.get_json(:b)
58
+ json.should == '{"b":2}'
59
+ end
60
+
61
+ it 'should retrieve a key-value pair with a Nil value and JSON encode it' do
62
+ json = @hash.get_json(:c)
63
+ json.should == '{"c":null}'
64
+ end
65
+
66
+ it 'should retrieve a key-value pair with a Float value and JSON encode it' do
67
+ json = @hash.get_json(:float)
68
+ json.should == '{"float":3.14}'
69
+ end
70
+
71
+ it 'should retrieve a key-value pair with an Integer value and JSON encode it' do
72
+ json = @hash.get_json(:integer)
73
+ json.should == '{"integer":5}'
74
+ end
75
+ end
76
+
77
+ context '#store_json' do
78
+ before(:each) do
79
+ @new_hash = JSONSerializableHashTestHash.new
80
+ @new_hash.store_json('{"a":"a"}')
81
+ end
82
+
83
+ it 'should use symbols for the keys instead of strings or other objects' do
84
+ @new_hash.has_key?(:a).should be_true
85
+ @new_hash.has_key?('a').should be_false
86
+ end
87
+
88
+ it 'should parse the provided JSON and store it as a key-value pair' do
89
+ @new_hash[:a].should == 'a'
90
+ end
91
+
92
+ it 'should parse the provided JSON and replace an existing key-value pair' do
93
+ @new_hash.store_json('{"a":"b"}')
94
+ @new_hash[:a].should == 'b'
95
+ end
96
+ end
97
+ end
98
+ end
@@ -5,8 +5,12 @@ describe "AttributeKit" do
5
5
  defined?(AttributeKit).should == 'constant'
6
6
  end
7
7
 
8
- describe "::AttributeHash" do
9
- describe '#new' do
8
+ context "::AttributeHash" do
9
+ it 'loads' do
10
+ defined?(AttributeKit::AttributeHash).should == 'constant'
11
+ end
12
+
13
+ context '#new' do
10
14
  it "should return an empty AttributeHash when initialized without arguments" do
11
15
  test_hash = AttributeKit::AttributeHash.new
12
16
  test_hash.empty?.should be_true
@@ -32,7 +36,7 @@ describe "AttributeKit" do
32
36
  end
33
37
  end
34
38
 
35
- describe '#[]=' do
39
+ context '#[]=' do
36
40
  before(:each) do
37
41
  @test_hash = AttributeKit::AttributeHash.new
38
42
  @test_hash[:blue] = 'blue'
@@ -61,7 +65,7 @@ describe "AttributeKit" do
61
65
  end
62
66
  end
63
67
 
64
- describe '#store' do
68
+ context '#store' do
65
69
  before(:each) do
66
70
  @test_hash = AttributeKit::AttributeHash.new
67
71
  @test_hash.store(:blue, 'blue')
@@ -86,7 +90,7 @@ describe "AttributeKit" do
86
90
  end
87
91
  end
88
92
 
89
- describe '#[]' do
93
+ context '#[]' do
90
94
  before(:each) do
91
95
  @test_hash = AttributeKit::AttributeHash.new('red')
92
96
  @test_hash[:blue] = 'blue'
@@ -103,7 +107,7 @@ describe "AttributeKit" do
103
107
  end
104
108
  end
105
109
 
106
- describe '#delete' do
110
+ context '#delete' do
107
111
  before(:each) do
108
112
  @test_hash = AttributeKit::AttributeHash.new
109
113
  @test_hash[:blue] = 'blue'
@@ -133,7 +137,7 @@ describe "AttributeKit" do
133
137
  end
134
138
  end
135
139
 
136
- describe '#delete_if' do
140
+ context '#delete_if' do
137
141
  before(:each) do
138
142
  @test_hash = AttributeKit::AttributeHash.new
139
143
  @test_hash[:blue] = 'blue'
@@ -176,7 +180,7 @@ describe "AttributeKit" do
176
180
  end
177
181
  end
178
182
 
179
- describe '#keep_if' do
183
+ context '#keep_if' do
180
184
  before(:each) do
181
185
  @test_hash = AttributeKit::AttributeHash.new
182
186
  @test_hash[:blue] = 'blue'
@@ -219,7 +223,7 @@ describe "AttributeKit" do
219
223
  end
220
224
  end
221
225
 
222
- describe '#reject!' do
226
+ context '#reject!' do
223
227
  before(:each) do
224
228
  @test_hash = AttributeKit::AttributeHash.new
225
229
  @test_hash[:blue] = 'blue'
@@ -270,7 +274,7 @@ describe "AttributeKit" do
270
274
  end
271
275
  end
272
276
 
273
- describe '#select!' do
277
+ context '#select!' do
274
278
  before(:each) do
275
279
  @test_hash = AttributeKit::AttributeHash.new
276
280
  @test_hash[:blue] = 'blue'
@@ -321,7 +325,7 @@ describe "AttributeKit" do
321
325
  end
322
326
  end
323
327
 
324
- describe "#replace" do
328
+ context "#replace" do
325
329
  before(:each) do
326
330
  @test_hash = AttributeKit::AttributeHash.new
327
331
  @test_hash[:blue] = 'blue'
@@ -370,7 +374,7 @@ describe "AttributeKit" do
370
374
  end
371
375
  end
372
376
 
373
- describe "#merge!" do
377
+ context "#merge!" do
374
378
  before(:each) do
375
379
  @test_hash = AttributeKit::AttributeHash.new
376
380
  @test_hash[:blue] = 'blue'
@@ -433,7 +437,7 @@ describe "AttributeKit" do
433
437
  end
434
438
  end
435
439
 
436
- describe "#update" do
440
+ context "#update" do
437
441
  before(:each) do
438
442
  @test_hash = AttributeKit::AttributeHash.new
439
443
  @test_hash[:blue] = 'blue'
@@ -496,7 +500,7 @@ describe "AttributeKit" do
496
500
  end
497
501
  end
498
502
 
499
- describe "#shift" do
503
+ context "#shift" do
500
504
  before(:each) do
501
505
  @test_hash = AttributeKit::AttributeHash.new
502
506
  @test_hash[:blue] = 'blue'
@@ -551,7 +555,7 @@ describe "AttributeKit" do
551
555
  end
552
556
  end
553
557
 
554
- describe "#clear" do
558
+ context "#clear" do
555
559
  before(:each) do
556
560
  @test_hash = AttributeKit::AttributeHash.new
557
561
  @test_hash[:blue] = 'blue'
@@ -584,7 +588,7 @@ describe "AttributeKit" do
584
588
  end
585
589
  end
586
590
 
587
- describe '#clean_attributes' do
591
+ context '#clean_attributes' do
588
592
  before(:each) do
589
593
  @test_hash = AttributeKit::AttributeHash.new
590
594
  @test_hash[:blue] = 'blue'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: attribute-kit
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.4
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jonathan Mischo
@@ -10,55 +10,55 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-15 00:00:00 -07:00
13
+ date: 2011-07-16 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
- name: rspec
17
+ name: yajl-ruby
18
18
  requirement: &id001 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
- - - ~>
21
+ - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 2.3.0
23
+ version: 0.8.2
24
24
  type: :development
25
25
  prerelease: false
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: rspec
29
29
  requirement: &id002 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: 1.0.0
34
+ version: 2.3.0
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
- name: jeweler
39
+ name: bundler
40
40
  requirement: &id003 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 1.6.4
45
+ version: 1.0.0
46
46
  type: :development
47
47
  prerelease: false
48
48
  version_requirements: *id003
49
49
  - !ruby/object:Gem::Dependency
50
- name: rcov
50
+ name: jeweler
51
51
  requirement: &id004 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
- - - ">="
54
+ - - ~>
55
55
  - !ruby/object:Gem::Version
56
- version: "0"
56
+ version: 1.6.4
57
57
  type: :development
58
58
  prerelease: false
59
59
  version_requirements: *id004
60
60
  - !ruby/object:Gem::Dependency
61
- name: yard
61
+ name: rcov
62
62
  requirement: &id005 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
@@ -69,7 +69,7 @@ dependencies:
69
69
  prerelease: false
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
72
- name: rdiscount
72
+ name: yard
73
73
  requirement: &id006 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
@@ -79,6 +79,17 @@ dependencies:
79
79
  type: :development
80
80
  prerelease: false
81
81
  version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: rdiscount
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: *id007
82
93
  description: Tools for attribute tracking like Hashes with dirty tracking and events, for building hybrid models and generally going beyond what's provided by your local ORM/DRM, while allowing you to expand what you can do with them, live without them, or roll your own
83
94
  email: jon.mischo@gmail.com
84
95
  executables: []
@@ -98,6 +109,8 @@ files:
98
109
  - lib/attribute-kit.rb
99
110
  - lib/attribute-kit/attribute-kit.rb
100
111
  - lib/attribute-kit/attribute_hash.rb
112
+ - lib/attribute-kit/json_serializable_hash.rb
113
+ - spec/AttributeKit/json_serializable_hash_spec.rb
101
114
  - spec/attribute-kit_spec.rb
102
115
  - spec/spec_helper.rb
103
116
  has_rdoc: true
@@ -114,7 +127,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
127
  requirements:
115
128
  - - ">="
116
129
  - !ruby/object:Gem::Version
117
- hash: 464791598370222701
130
+ hash: -293996943625060104
118
131
  segments:
119
132
  - 0
120
133
  version: "0"