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 +1 -0
- data/Gemfile.lock +2 -0
- data/README.markdown +94 -1
- data/VERSION +1 -1
- data/lib/attribute-kit/attribute-kit.rb +1 -0
- data/lib/attribute-kit/attribute_hash.rb +43 -1
- data/lib/attribute-kit/json_serializable_hash.rb +107 -0
- data/spec/AttributeKit/json_serializable_hash_spec.rb +98 -0
- data/spec/attribute-kit_spec.rb +20 -16
- metadata +28 -15
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.markdown
CHANGED
@@ -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
|
+
0.2.0
|
@@ -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
|
data/spec/attribute-kit_spec.rb
CHANGED
@@ -5,8 +5,12 @@ describe "AttributeKit" do
|
|
5
5
|
defined?(AttributeKit).should == 'constant'
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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-
|
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:
|
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:
|
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:
|
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:
|
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:
|
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.
|
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:
|
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:
|
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:
|
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:
|
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:
|
130
|
+
hash: -293996943625060104
|
118
131
|
segments:
|
119
132
|
- 0
|
120
133
|
version: "0"
|