matic 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +33 -10
- data/lib/matic.rb +17 -27
- data/lib/matic/version.rb +1 -1
- data/spec/matic_spec.rb +119 -72
- data/spec/models/book.rb +8 -0
- data/spec/models/person.rb +2 -2
- metadata +6 -4
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,31 +1,54 @@
|
|
1
1
|
# Matic
|
2
2
|
|
3
|
-
Matic adds attribute accessors and dirty tracking to Mongomatic
|
3
|
+
Matic adds attribute accessors and dirty tracking to Mongomatic and
|
4
|
+
optionally shortens field names to optimize storing and indexing.
|
4
5
|
|
5
6
|
## Examples
|
6
7
|
|
7
8
|
class Person < Mongomatic::Base
|
8
9
|
include Matic
|
9
10
|
|
10
|
-
|
11
|
+
fields :first_name,
|
12
|
+
:last_name
|
11
13
|
end
|
12
14
|
|
13
15
|
person = Person.new
|
14
|
-
person.
|
16
|
+
person.first_name = "John"
|
15
17
|
|
16
|
-
person.
|
18
|
+
person.first_name_changed?
|
17
19
|
=> true
|
18
20
|
|
19
|
-
person.changes["
|
20
|
-
=> [nil, "John
|
21
|
+
person.changes["first_name"]
|
22
|
+
=> [nil, "John"]
|
21
23
|
|
22
24
|
person.insert
|
23
25
|
|
24
|
-
person.
|
26
|
+
person.first_name_changed?
|
25
27
|
=> false
|
26
28
|
|
27
|
-
person.changes["
|
29
|
+
person.changes["first_name"]
|
28
30
|
=> nil
|
29
31
|
|
30
|
-
person.previous_changes["
|
31
|
-
=> [nil, "John
|
32
|
+
person.previous_changes["first_name"]
|
33
|
+
=> [nil, "John"]
|
34
|
+
|
35
|
+
This is a model with short field names:
|
36
|
+
|
37
|
+
class Person < Mongomatic::Base
|
38
|
+
include Matic
|
39
|
+
|
40
|
+
fields :first_name => 'f',
|
41
|
+
:last_name => 'l'
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
person = Person.new
|
46
|
+
|
47
|
+
person.first_name = "John"
|
48
|
+
person.last_name = "Doe"
|
49
|
+
|
50
|
+
person.insert
|
51
|
+
=> #<Person:0x000001023cea30
|
52
|
+
@doc=
|
53
|
+
{"f"=>"John", "l" => "Doe", "_id"=>BSON::ObjectId('4cdd1b0c6aa2b112e1000001')}
|
54
|
+
...>
|
data/lib/matic.rb
CHANGED
@@ -9,33 +9,31 @@ module Matic
|
|
9
9
|
self.name.tableize
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
12
|
+
def fields(*attrs)
|
13
|
+
if attrs.first.is_a? Hash
|
14
|
+
attrs.first.each { |k, v| define_accessor(k, v) }
|
15
|
+
define_attribute_methods(attrs.first.keys)
|
16
|
+
else
|
17
|
+
attrs.each { |k, v| define_accessor(k, v) }
|
18
|
+
define_attribute_methods(attrs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def define_accessor(attr_name, attr_field=nil)
|
25
|
+
attr_field ||= attr_name
|
14
26
|
|
15
27
|
define_method(attr_name) do
|
16
|
-
self[
|
28
|
+
self[attr_field.to_s]
|
17
29
|
end
|
18
30
|
|
19
31
|
define_method("#{attr_name}=") do |val|
|
20
|
-
unless val == self[
|
32
|
+
unless val == self[attr_field.to_s]
|
21
33
|
eval("#{attr_name}_will_change!")
|
22
34
|
end
|
23
35
|
|
24
|
-
self[
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def generate_attribute_methods(attr_name)
|
31
|
-
attribute_method_matchers.each do |matcher|
|
32
|
-
method_name = matcher.method_name(attr_name)
|
33
|
-
|
34
|
-
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
35
|
-
def #{method_name}(*args)
|
36
|
-
send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
|
37
|
-
end
|
38
|
-
STR
|
36
|
+
self[attr_field.to_s] = val
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
@@ -44,18 +42,10 @@ module Matic
|
|
44
42
|
clear_changes if super
|
45
43
|
end
|
46
44
|
|
47
|
-
def insert!(opts={})
|
48
|
-
insert(opts.merge(:safe => true))
|
49
|
-
end
|
50
|
-
|
51
45
|
def update(opts={}, update_doc=@doc)
|
52
46
|
clear_changes if super
|
53
47
|
end
|
54
48
|
|
55
|
-
def update!(opts={}, update_doc=@doc)
|
56
|
-
update(opts.merge(:safe => true), update_doc)
|
57
|
-
end
|
58
|
-
|
59
49
|
def save
|
60
50
|
is_new ? insert : update
|
61
51
|
end
|
data/lib/matic/version.rb
CHANGED
data/spec/matic_spec.rb
CHANGED
@@ -1,137 +1,184 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe "
|
3
|
+
describe "a mongomatic model that includes matic" do
|
4
4
|
|
5
5
|
let(:person) { Person.new }
|
6
|
+
let(:book) { Book.new }
|
6
7
|
|
7
8
|
it "has a collection first_name" do
|
8
9
|
person.class.collection_name.should eql "people"
|
9
10
|
end
|
10
11
|
|
11
|
-
describe ".
|
12
|
-
it "defines a getter" do
|
13
|
-
person["first_name"] = "John"
|
12
|
+
describe ".fields" do
|
14
13
|
|
15
|
-
|
16
|
-
lambda { person.foo }.should raise_error NoMethodError
|
17
|
-
end
|
14
|
+
context "when it is passed an array" do
|
18
15
|
|
19
|
-
|
20
|
-
|
16
|
+
it "defines a getter" do
|
17
|
+
person["first_name"] = "John"
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
person.first_name.should eql "John"
|
20
|
+
lambda { person.foo }.should raise_error NoMethodError
|
21
|
+
end
|
22
|
+
|
23
|
+
it "defines a setter" do
|
24
|
+
person.first_name = "John"
|
26
25
|
|
27
|
-
|
26
|
+
person["first_name"].should eql "John"
|
27
|
+
lambda { person.foo= "bar" }.should raise_error NoMethodError
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
28
31
|
|
29
|
-
|
32
|
+
context "when it is passed a hash" do
|
30
33
|
|
31
|
-
it "
|
32
|
-
|
33
|
-
|
34
|
+
it "defines a getter" do
|
35
|
+
book["i"] = "9780485113358"
|
36
|
+
book.isbn.should eql "9780485113358"
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
book["a"] = ["Gilles Deleuze"]
|
39
|
+
book.authors.should eql ["Gilles Deleuze"]
|
37
40
|
end
|
38
41
|
|
39
|
-
it "
|
40
|
-
|
42
|
+
it "defines a setter" do
|
43
|
+
book.isbn = "9780485113358"
|
44
|
+
book["i"].should eql "9780485113358"
|
45
|
+
|
46
|
+
book.authors = ["Gilles Deleuze"]
|
47
|
+
book["a"].should eql ["Gilles Deleuze"]
|
41
48
|
end
|
42
49
|
|
50
|
+
it "stores documents with short field names" do
|
51
|
+
book.isbn = "9780485113358"
|
52
|
+
book.insert
|
53
|
+
|
54
|
+
book.instance_variable_get(:@doc).should have_key 'i'
|
55
|
+
end
|
43
56
|
end
|
44
57
|
|
45
|
-
|
58
|
+
end
|
46
59
|
|
47
|
-
|
48
|
-
person.first_name_changed?.should be_true
|
49
|
-
person.last_name_changed?.should be_true
|
50
|
-
end
|
60
|
+
shared_examples_for "a dirty-tracking command" do
|
51
61
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
62
|
+
it "marks a current change as previous" do
|
63
|
+
person.first_name_changed?.should be_false
|
64
|
+
person.previous_changes["first_name"].should eql [nil, "John"]
|
56
65
|
|
66
|
+
person.last_name_changed?.should be_false
|
67
|
+
person.previous_changes["last_name"].should eql [nil, "Doe"]
|
57
68
|
end
|
58
69
|
|
59
|
-
|
70
|
+
it "does callbacks" do
|
71
|
+
person.instance_variable_get(:@called_back).should be_true
|
72
|
+
end
|
60
73
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "a dirty-tracking setter" do
|
65
77
|
|
66
|
-
|
78
|
+
context "when an attribute is set" do
|
67
79
|
|
68
|
-
|
80
|
+
context "and its value has changed" do
|
69
81
|
|
70
|
-
before
|
82
|
+
before do
|
83
|
+
person.first_name = "John"
|
84
|
+
end
|
71
85
|
|
72
|
-
|
86
|
+
it "marks the attribute as changed" do
|
87
|
+
person.first_name_changed?.should be_true
|
88
|
+
end
|
89
|
+
|
90
|
+
it "remembers changes to the attribute" do
|
91
|
+
person.changes["first_name"].should eql [nil, "John"]
|
92
|
+
end
|
73
93
|
|
74
94
|
end
|
75
95
|
|
76
|
-
|
96
|
+
context "and its value has not changed" do
|
77
97
|
|
78
|
-
before
|
98
|
+
before do
|
99
|
+
person.first_name = nil
|
100
|
+
end
|
79
101
|
|
80
|
-
|
102
|
+
it "does not mark the attribute as changed" do
|
103
|
+
person.first_name_changed?.should be_false
|
104
|
+
end
|
81
105
|
|
82
106
|
end
|
83
107
|
|
84
|
-
|
108
|
+
end
|
85
109
|
|
86
|
-
|
110
|
+
end
|
87
111
|
|
88
|
-
|
112
|
+
context "when object is new" do
|
89
113
|
|
90
|
-
|
114
|
+
before do
|
115
|
+
person.first_name = "John"
|
116
|
+
person.last_name = "Doe"
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#insert" do
|
120
|
+
|
121
|
+
before { person.insert }
|
122
|
+
|
123
|
+
it_behaves_like "a dirty-tracking command"
|
91
124
|
|
92
125
|
end
|
93
126
|
|
94
|
-
|
127
|
+
describe "#insert!" do
|
95
128
|
|
96
|
-
before
|
97
|
-
person.insert
|
98
|
-
person.instance_variable_set(:@called_back, false)
|
99
|
-
person.first_name = "John"
|
100
|
-
person.last_name = "Doe"
|
101
|
-
end
|
129
|
+
before { person.insert! }
|
102
130
|
|
103
|
-
it_behaves_like "a dirty
|
131
|
+
it_behaves_like "a dirty-tracking command"
|
104
132
|
|
105
|
-
|
133
|
+
end
|
106
134
|
|
107
|
-
|
135
|
+
describe "#save" do
|
108
136
|
|
109
|
-
|
137
|
+
before { person.save }
|
110
138
|
|
111
|
-
|
139
|
+
it_behaves_like "a dirty-tracking command"
|
112
140
|
|
113
|
-
|
141
|
+
end
|
114
142
|
|
115
|
-
|
143
|
+
end
|
116
144
|
|
117
|
-
|
145
|
+
context "when object is not new" do
|
118
146
|
|
119
|
-
|
147
|
+
before do
|
148
|
+
person.insert
|
149
|
+
person.instance_variable_set(:@called_back, false)
|
150
|
+
person.first_name = "John"
|
151
|
+
person.last_name = "Doe"
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#update" do
|
155
|
+
|
156
|
+
before { person.update }
|
157
|
+
|
158
|
+
it_behaves_like "a dirty-tracking command"
|
120
159
|
|
121
160
|
end
|
122
161
|
|
123
|
-
|
162
|
+
describe "#update!" do
|
124
163
|
|
125
|
-
before
|
126
|
-
person.stub!(:valid?).and_return(false)
|
127
|
-
person.first_name = "John"
|
128
|
-
end
|
164
|
+
before { person.update! }
|
129
165
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
166
|
+
it_behaves_like "a dirty-tracking command"
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when an invalid object is saved" do
|
173
|
+
|
174
|
+
before do
|
175
|
+
person.stub!(:valid?).and_return(false)
|
176
|
+
person.first_name = "John"
|
177
|
+
end
|
134
178
|
|
179
|
+
it "does not clear changes" do
|
180
|
+
person.save
|
181
|
+
person.first_name_changed?.should be_true
|
135
182
|
end
|
136
183
|
|
137
184
|
end
|
data/spec/models/book.rb
ADDED
data/spec/models/person.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Hakan Ensari
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-12 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- lib/matic/version.rb
|
131
131
|
- matic.gemspec
|
132
132
|
- spec/matic_spec.rb
|
133
|
+
- spec/models/book.rb
|
133
134
|
- spec/models/person.rb
|
134
135
|
- spec/spec_helper.rb
|
135
136
|
- spec/support/mongomatic.rb
|
@@ -168,6 +169,7 @@ specification_version: 3
|
|
168
169
|
summary: Mongomatic with attribute accessors and dirty tracking
|
169
170
|
test_files:
|
170
171
|
- spec/matic_spec.rb
|
172
|
+
- spec/models/book.rb
|
171
173
|
- spec/models/person.rb
|
172
174
|
- spec/spec_helper.rb
|
173
175
|
- spec/support/mongomatic.rb
|