no_integrity 0.4.0 → 0.5.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/Gemfile +1 -1
- data/README.md +27 -10
- data/lib/no_integrity/no_integrity.rb +40 -40
- data/lib/no_integrity/version.rb +1 -1
- data/no_integrity.gemspec +2 -3
- data/spec/no_integrity_spec.rb +48 -44
- data/spec/spec_helper.rb +15 -10
- metadata +9 -26
- data/autotest/discover.rb +0 -1
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,35 +9,52 @@ Simple hash serialization with loose type coercion. Built for ActiveRecord mode
|
|
9
9
|
For starters, throw this in your Gemfile:
|
10
10
|
|
11
11
|
gem "no_integrity"
|
12
|
-
|
12
|
+
|
13
13
|
Then, add this to your class:
|
14
14
|
|
15
15
|
class MrArbitrary < ActiveRecord::Base
|
16
16
|
include NoIntegrity
|
17
|
-
|
17
|
+
|
18
18
|
attr_accessor :some_random_hash
|
19
|
-
|
20
|
-
no_attr_store :some_random_hash
|
19
|
+
|
21
20
|
no_attribute :misc
|
22
|
-
no_attribute :hair
|
23
|
-
no_attribute :age
|
24
|
-
no_attribute :height
|
25
|
-
no_attribute
|
21
|
+
no_attribute :hair, type: 'String'
|
22
|
+
no_attribute :age, type: 'Integer'
|
23
|
+
no_attribute :height, type: 'String'
|
24
|
+
no_attribute :eyes, type: 'String'
|
25
|
+
no_attribute :friendly, type: 'Boolean', default: true
|
26
|
+
no_attribute :cheese
|
27
|
+
no_attribute :ham
|
28
|
+
no_attribute :balogne
|
26
29
|
end
|
27
|
-
|
30
|
+
|
28
31
|
Finally, you can make calls like this:
|
29
32
|
|
30
33
|
arbs = MrArbitrary.new
|
31
34
|
arbs.friendly? # => false
|
32
35
|
arbs.friendly = true
|
33
36
|
arbs.friendly? # => true
|
34
|
-
|
37
|
+
|
35
38
|
You can define as many attributes as you want, and you can specify any of the following coercion types:
|
36
39
|
|
37
40
|
1. `String`
|
38
41
|
2. `Integer`
|
39
42
|
3. `Boolean`
|
40
43
|
|
44
|
+
## Upgrading From 0.4.0
|
45
|
+
|
46
|
+
For `0.5.0` I added the ability to store default values for each of the attributes. This required some changes to the way that attributes were setup and stored for each object.
|
47
|
+
|
48
|
+
In your classes you'll need to convert from:
|
49
|
+
|
50
|
+
no_attribute hair: 'String'
|
51
|
+
|
52
|
+
To:
|
53
|
+
|
54
|
+
no_attribute :hair, type: 'String'
|
55
|
+
|
56
|
+
Also if you relied on any of the undocumented method calls, you'll need to update them so they can handle the new internal structure.
|
57
|
+
|
41
58
|
## Why?
|
42
59
|
|
43
60
|
A while back, I needed serialized attributes but it either didn't work for my use case or it wasn't made yet. So, I wrote this gem.
|
@@ -1,54 +1,48 @@
|
|
1
1
|
module NoIntegrity
|
2
|
-
|
2
|
+
|
3
3
|
def self.included(a_module)
|
4
4
|
a_module.module_eval do
|
5
5
|
extend ClassMethods
|
6
6
|
end
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
module ClassMethods
|
10
10
|
def no_attr_store(storage_attribute = nil)
|
11
11
|
if storage_attribute && @no_attr_store.nil?
|
12
12
|
alias_no_attr_store(storage_attribute)
|
13
13
|
@no_attr_store = storage_attribute
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
return @no_attr_store
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def no_attributes
|
20
20
|
@no_attributes || { }
|
21
21
|
end
|
22
|
-
|
23
|
-
def no_attribute(options)
|
22
|
+
|
23
|
+
def no_attribute(attribs, options = { })
|
24
24
|
@no_attributes ||= { }
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
options.each do |attrib|
|
33
|
-
@no_attributes[attrib] = nil
|
34
|
-
setup_no_attribute_accessors(attrib, nil)
|
35
|
-
end
|
36
|
-
elsif options.is_a?(Symbol)
|
37
|
-
setup_no_attribute_accessors(options)
|
25
|
+
|
26
|
+
attribs = [attribs] unless attribs.is_a?(Array)
|
27
|
+
|
28
|
+
attribs.each do |attrib|
|
29
|
+
@no_attributes[attrib.to_sym] = options
|
30
|
+
setup_no_attribute_accessors(attrib, options[:type])
|
31
|
+
update_no_attribute_mappings(attrib, options)
|
38
32
|
end
|
39
33
|
end
|
40
|
-
|
34
|
+
|
41
35
|
def no_attribute_mappings
|
42
36
|
@no_attribute_mappings
|
43
37
|
end
|
44
|
-
|
38
|
+
|
45
39
|
private
|
46
|
-
|
47
|
-
def update_no_attribute_mappings(attrib,
|
40
|
+
|
41
|
+
def update_no_attribute_mappings(attrib, options)
|
48
42
|
@no_attribute_mappings ||= { }
|
49
|
-
@no_attribute_mappings[attrib.
|
43
|
+
@no_attribute_mappings[attrib.to_sym] = options
|
50
44
|
end
|
51
|
-
|
45
|
+
|
52
46
|
def setup_no_attribute_accessors(attrib, coercion_type = nil)
|
53
47
|
module_eval <<-STR
|
54
48
|
def #{attrib}; get_no_attribute('#{attrib}'); end
|
@@ -56,7 +50,7 @@ module NoIntegrity
|
|
56
50
|
def #{attrib}=(v); set_no_attribute('#{attrib}', coerce_no_attribute_type(v, '#{coercion_type}')); end
|
57
51
|
STR
|
58
52
|
end
|
59
|
-
|
53
|
+
|
60
54
|
def alias_no_attr_store(old_name)
|
61
55
|
module_eval <<-STR, __FILE__, __LINE__ + 1
|
62
56
|
def __no_attr_store; self.#{old_name}; end
|
@@ -64,13 +58,17 @@ module NoIntegrity
|
|
64
58
|
def __no_attr_store=(v); self.#{old_name} = v; end
|
65
59
|
STR
|
66
60
|
end
|
67
|
-
|
61
|
+
|
68
62
|
end
|
69
|
-
|
63
|
+
|
70
64
|
def no_attributes
|
71
65
|
self.class.no_attributes
|
72
66
|
end
|
73
|
-
|
67
|
+
|
68
|
+
def no_attribute_mappings
|
69
|
+
self.class.no_attribute_mappings
|
70
|
+
end
|
71
|
+
|
74
72
|
def update_no_attributes(new_attributes)
|
75
73
|
raise "Type mismatch: I received a #{new_attributes.class} when I was expecting a Hash." unless new_attributes.is_a?(Hash)
|
76
74
|
new_attributes.each do |key, value|
|
@@ -78,31 +76,33 @@ module NoIntegrity
|
|
78
76
|
end
|
79
77
|
return self.send(self.class.no_attr_store)
|
80
78
|
end
|
81
|
-
|
79
|
+
|
82
80
|
private
|
83
|
-
|
81
|
+
|
84
82
|
def get_no_attribute(attribute_name)
|
85
83
|
return nil unless self.__no_attr_store.is_a?(Hash)
|
86
84
|
self.__no_attr_store = normalize_keys(__no_attr_store)
|
87
|
-
self.__no_attr_store[attribute_name.
|
85
|
+
no_val = self.__no_attr_store[attribute_name.to_sym]
|
86
|
+
|
87
|
+
no_val.nil? ? no_attribute_mappings[attribute_name.to_sym][:default] : no_val
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
def set_no_attribute(attribute_name, value)
|
91
91
|
self.__no_attr_store = normalize_keys(__no_attr_store)
|
92
92
|
if self.__no_attr_store.is_a?(Hash)
|
93
|
-
self.__no_attr_store[attribute_name.
|
93
|
+
self.__no_attr_store[attribute_name.to_sym] = value
|
94
94
|
else
|
95
|
-
self.__no_attr_store = { attribute_name.
|
95
|
+
self.__no_attr_store = { attribute_name.to_sym => value }
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
def normalize_keys(store)
|
100
100
|
return store if @__performed_key_normalization || !store.is_a?(Hash)
|
101
|
-
store.keys.each { |key| store[key.
|
101
|
+
store.keys.each { |key| store[key.to_sym] = store.delete(key) }
|
102
102
|
@__performed_key_normalization = true
|
103
103
|
return store
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
def coerce_no_attribute_type(value, type)
|
107
107
|
return value if (type == nil) || (type == '')
|
108
108
|
value = case type
|
@@ -117,8 +117,8 @@ module NoIntegrity
|
|
117
117
|
else
|
118
118
|
raise "Unsure of what to do with #{type}!!"
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
return value
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
end
|
data/lib/no_integrity/version.rb
CHANGED
data/no_integrity.gemspec
CHANGED
@@ -16,7 +16,6 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
-
|
20
|
-
gem.add_development_dependency(%q<rspec>, ["
|
21
|
-
gem.add_development_dependency(%q<ZenTest>, ["= 4.5.0"])
|
19
|
+
|
20
|
+
gem.add_development_dependency(%q<rspec>, ["~> 3.4.0"])
|
22
21
|
end
|
data/spec/no_integrity_spec.rb
CHANGED
@@ -5,12 +5,12 @@ describe NoIntegrity do
|
|
5
5
|
context "class methods" do
|
6
6
|
|
7
7
|
it "stores mappings of the various types of attributes" do
|
8
|
-
MrArbitrary.no_attribute_mappings[
|
9
|
-
MrArbitrary.no_attribute_mappings[
|
8
|
+
expect(MrArbitrary.no_attribute_mappings[:hair][:type]).to eq('String')
|
9
|
+
expect(MrArbitrary.no_attribute_mappings[:friendly][:type]).to eq('Boolean')
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
context "An object with NoIntegrity" do
|
15
15
|
|
16
16
|
before(:each) do
|
@@ -21,97 +21,101 @@ describe NoIntegrity do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should know where the attributes are being stored" do
|
24
|
-
@arbs.class.no_attr_store.
|
24
|
+
expect(@arbs.class.no_attr_store).to be_an_instance_of Symbol
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should be able to get all of the attributes" do
|
28
|
-
@arbs.__no_attr_store.
|
28
|
+
expect(@arbs.__no_attr_store).to be_an_instance_of Hash
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
it "should be able to list the attributes it is familiar with" do
|
32
|
-
@arbs.no_attributes.
|
32
|
+
expect(@arbs.no_attributes).to be_an_instance_of Hash
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should be able to retrieve attributes from the store" do
|
36
|
-
@arbs.hair.
|
36
|
+
expect(@arbs.hair).to eq('brown')
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should be able to have an attribute assigned" do
|
40
40
|
@arbs.hair = "black"
|
41
|
-
@arbs.hair.
|
41
|
+
expect(@arbs.hair).to eq('black')
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
it "should be able to mass assign attributes" do
|
45
45
|
@arbs.update_no_attributes( :hair => 'blonde' )
|
46
|
-
@arbs.hair.
|
46
|
+
expect(@arbs.hair).to eq('blonde')
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
it "should coerce boolean types" do
|
50
50
|
@arbs.friendly = 1
|
51
|
-
@arbs.
|
52
|
-
@arbs.friendly.
|
51
|
+
expect(@arbs).to be_friendly
|
52
|
+
expect(@arbs.friendly).to eq(true)
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
it "should coerce interger types" do
|
56
56
|
@arbs.age = "25"
|
57
|
-
@arbs.age.
|
57
|
+
expect(@arbs.age).to eq(25)
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
it "should allow arbitrary types" do
|
61
61
|
@arbs.misc = ['junk']
|
62
|
-
@arbs.misc.
|
62
|
+
expect(@arbs.misc).to eq(['junk'])
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
it "should allow for arrays of arbitary types" do
|
66
|
-
@arbs.no_attributes.keys.
|
67
|
-
@arbs.no_attributes.keys.
|
68
|
-
@arbs.no_attributes.keys.
|
66
|
+
expect(@arbs.no_attributes.keys).to include(:cheese)
|
67
|
+
expect(@arbs.no_attributes.keys).to include(:ham)
|
68
|
+
expect(@arbs.no_attributes.keys).to include(:balogne)
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it "should allow for hashes of types" do
|
72
|
-
@arbs.no_attributes.keys.
|
73
|
-
@arbs.no_attributes.keys.
|
74
|
-
@arbs.no_attributes.keys.
|
72
|
+
expect(@arbs.no_attributes.keys).to include(:height)
|
73
|
+
expect(@arbs.no_attributes.keys).to include(:eyes)
|
74
|
+
expect(@arbs.no_attributes.keys).to include(:friendly)
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
it "should coerce types on mass assignment" do
|
78
78
|
@arbs.update_no_attributes(:age => "22")
|
79
|
-
@arbs.age.
|
79
|
+
expect(@arbs.age).to eq(22)
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
it "should coerce booleans from numbers" do
|
83
83
|
@arbs.friendly = "0"
|
84
|
-
@arbs.
|
84
|
+
expect(@arbs).not_to be_friendly
|
85
85
|
@arbs.friendly = "1"
|
86
|
-
@arbs.
|
86
|
+
expect(@arbs).to be_friendly
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
it "should coerce booleans from strings" do
|
90
90
|
@arbs.friendly = "false"
|
91
|
-
@arbs.
|
91
|
+
expect(@arbs).not_to be_friendly
|
92
92
|
@arbs.friendly = "true"
|
93
|
-
@arbs.
|
93
|
+
expect(@arbs).to be_friendly
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it "should not allow mass assignment of attributes if they are not in a hash" do
|
97
|
-
|
97
|
+
expect { @arbs.update_no_attributes("monkey") }.to raise_exception("Type mismatch: I received a String when I was expecting a Hash.")
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
it "should return nil for every attribute if the store is not a hash" do
|
101
101
|
@arbs.some_random_hash = nil
|
102
|
-
@arbs.hair.
|
102
|
+
expect(@arbs.hair).to be_nil
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
it "should set the store to a hash when setting an attribute" do
|
106
106
|
@arbs.some_random_hash = "POTATO"
|
107
107
|
@arbs.eyes = 'red'
|
108
|
-
@arbs.eyes.
|
108
|
+
expect(@arbs.eyes).to eq('red')
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
it "should return an empty hash if there are no defined attributes" do
|
112
|
-
@arbs.no_attributes.
|
112
|
+
expect(@arbs.no_attributes).to be_an_instance_of(Hash)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns the default value" do
|
116
|
+
expect(@arbs.friendly).to eq true
|
113
117
|
end
|
114
118
|
|
115
119
|
end
|
116
|
-
|
120
|
+
|
117
121
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rspec'
|
3
|
-
require 'lib/no_integrity'
|
3
|
+
require './lib/no_integrity'
|
4
4
|
|
5
5
|
class MrArbitrary
|
6
6
|
include NoIntegrity
|
7
|
-
|
7
|
+
|
8
8
|
attr_accessor :some_random_hash
|
9
|
-
|
9
|
+
|
10
10
|
no_attr_store :some_random_hash
|
11
|
+
|
11
12
|
no_attribute :misc
|
12
|
-
no_attribute :hair
|
13
|
-
no_attribute :age
|
14
|
-
no_attribute :height
|
15
|
-
no_attribute
|
16
|
-
|
13
|
+
no_attribute :hair, type: 'String'
|
14
|
+
no_attribute :age, type: 'Integer'
|
15
|
+
no_attribute :height, type: 'String'
|
16
|
+
no_attribute :eyes, type: 'String'
|
17
|
+
no_attribute :friendly, type: 'Boolean', default: true
|
18
|
+
no_attribute :cheese
|
19
|
+
no_attribute :ham
|
20
|
+
no_attribute :balogne
|
21
|
+
|
17
22
|
def initialize(*args)
|
18
|
-
@some_random_hash ||= { :
|
23
|
+
@some_random_hash ||= { hair: 'brown' }
|
19
24
|
end
|
20
|
-
|
25
|
+
|
21
26
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: no_integrity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Patrick Tulskie
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2016-02-04 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -24,32 +24,16 @@ dependencies:
|
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 9
|
33
|
-
- 0
|
34
|
-
version: 2.9.0
|
35
|
-
type: :development
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: ZenTest
|
39
|
-
prerelease: false
|
40
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - "="
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
hash: 43
|
29
|
+
hash: 23
|
46
30
|
segments:
|
31
|
+
- 3
|
47
32
|
- 4
|
48
|
-
- 5
|
49
33
|
- 0
|
50
|
-
version: 4.
|
34
|
+
version: 3.4.0
|
51
35
|
type: :development
|
52
|
-
version_requirements: *
|
36
|
+
version_requirements: *id001
|
53
37
|
description: Add attributes without any sort of integrity to your ActiveRecord or other types of objects.
|
54
38
|
email:
|
55
39
|
- patricktulskie@gmail.com
|
@@ -64,7 +48,6 @@ files:
|
|
64
48
|
- Gemfile
|
65
49
|
- README.md
|
66
50
|
- Rakefile
|
67
|
-
- autotest/discover.rb
|
68
51
|
- lib/no_integrity.rb
|
69
52
|
- lib/no_integrity/no_integrity.rb
|
70
53
|
- lib/no_integrity/version.rb
|
data/autotest/discover.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Autotest.add_discovery { "rspec2" }
|