mongodoc 0.2.1 → 0.2.2

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.
Files changed (44) hide show
  1. data/README.textile +42 -12
  2. data/Rakefile +4 -4
  3. data/TODO +26 -0
  4. data/VERSION +1 -1
  5. data/examples/simple_document.rb +1 -1
  6. data/examples/simple_object.rb +0 -2
  7. data/features/mongodb.yml +6 -5
  8. data/features/removing_documents.feature +68 -0
  9. data/features/step_definitions/collection_steps.rb +3 -3
  10. data/features/step_definitions/document_steps.rb +2 -2
  11. data/features/step_definitions/removing_documents_steps.rb +14 -0
  12. data/features/support/support.rb +2 -2
  13. data/lib/mongodoc.rb +4 -7
  14. data/lib/mongodoc/associations/collection_proxy.rb +103 -0
  15. data/lib/mongodoc/associations/document_proxy.rb +53 -0
  16. data/lib/mongodoc/associations/hash_proxy.rb +96 -0
  17. data/lib/mongodoc/associations/proxy_base.rb +51 -0
  18. data/lib/mongodoc/attributes.rb +49 -17
  19. data/lib/mongodoc/collection.rb +15 -5
  20. data/lib/mongodoc/connection.rb +83 -20
  21. data/lib/mongodoc/criteria.rb +9 -4
  22. data/lib/mongodoc/cursor.rb +9 -3
  23. data/lib/mongodoc/document.rb +37 -24
  24. data/lib/mongodoc/validations/macros.rb +11 -0
  25. data/lib/mongodoc/validations/validates_embedded.rb +13 -0
  26. data/mongodb.example.yml +13 -5
  27. data/mongodoc.gemspec +33 -23
  28. data/spec/associations/collection_proxy_spec.rb +200 -0
  29. data/spec/associations/document_proxy_spec.rb +42 -0
  30. data/spec/associations/hash_proxy_spec.rb +163 -0
  31. data/spec/attributes_spec.rb +113 -47
  32. data/spec/bson_spec.rb +24 -24
  33. data/spec/collection_spec.rb +67 -86
  34. data/spec/connection_spec.rb +98 -150
  35. data/spec/criteria_spec.rb +4 -3
  36. data/spec/cursor_spec.rb +33 -27
  37. data/spec/document_spec.rb +173 -156
  38. data/spec/embedded_save_spec.rb +8 -3
  39. data/spec/new_record_spec.rb +33 -121
  40. metadata +80 -39
  41. data/lib/mongodoc/parent_proxy.rb +0 -44
  42. data/lib/mongodoc/proxy.rb +0 -83
  43. data/spec/parent_proxy_spec.rb +0 -44
  44. data/spec/proxy_spec.rb +0 -80
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe "MongoDoc::Associations::DocumentProxy" do
4
+ class Parent
5
+ include MongoDoc::Document
6
+ end
7
+
8
+ class Child
9
+ include MongoDoc::Document
10
+ end
11
+
12
+ let(:parent) { Parent.new }
13
+ let(:name) {'association'}
14
+
15
+ subject do
16
+ MongoDoc::Associations::DocumentProxy.new(:assoc_name => name, :root => parent, :parent => parent, :assoc_class => Child)
17
+ end
18
+
19
+ it "has the association name" do
20
+ subject.assoc_name.should == name
21
+ end
22
+
23
+ it "has the parent" do
24
+ subject._parent.should == parent
25
+ end
26
+
27
+ it "has the root" do
28
+ subject._root.should == parent
29
+ end
30
+
31
+ it "has the association class" do
32
+ subject.assoc_class.should == Child
33
+ end
34
+
35
+ it "inserts the association name the _path_to_root" do
36
+ subject._path_to_root(Child.new, :name1 => 'value1', :name2 => 'value2').should == {"#{name}.name1" => 'value1', "#{name}.name2" => "value2"}
37
+ end
38
+
39
+ it "#build builds a new object" do
40
+ Child.should === subject.build({})
41
+ end
42
+ end
@@ -0,0 +1,163 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '/spec_helper'))
2
+
3
+ describe MongoDoc::Associations::HashProxy do
4
+ class HashProxyTest
5
+ include MongoDoc::Document
6
+
7
+ key :name
8
+ end
9
+
10
+ let(:root) { stub('root', :register_save_observer => nil) }
11
+ let(:proxy) { MongoDoc::Associations::HashProxy.new(:assoc_name => 'has_many_name', :assoc_class => HashProxyTest, :root => root, :parent => root) }
12
+ let(:item) { HashProxyTest.new }
13
+ let(:other_item) {[1,2]}
14
+
15
+ context "#[]=" do
16
+ it "adds the item to the hash" do
17
+ proxy['new'] = item
18
+ proxy['new'].should == item
19
+ end
20
+
21
+ context "key names must be a string or symbol constrained by BSON element name" do
22
+ ['$invalid', 'in.valid', :_id, 'query', 1, Object.new].each do |name|
23
+ it "#{name} is invalid" do
24
+ expect do
25
+ proxy[name] = other_item
26
+ end.to raise_error(MongoDoc::InvalidEmbeddedHashKey)
27
+ end
28
+ end
29
+
30
+ [:key, 'key'].each do |name|
31
+ it "#{name} is a valid name" do
32
+ expect do
33
+ proxy[name] = other_item
34
+ end.to_not raise_error(MongoDoc::InvalidEmbeddedHashKey)
35
+ end
36
+ end
37
+ end
38
+
39
+ context "when the item is not a MongoDoc::Document" do
40
+
41
+ it "does not register a save observer" do
42
+ root.should_not_receive(:register_save_observer)
43
+ proxy['new'] = other_item
44
+ end
45
+
46
+ it "does not set the root" do
47
+ other_item.should_not_receive(:_root=)
48
+ proxy['new'] = other_item
49
+ end
50
+ end
51
+
52
+ context "when the item is a MongoDoc::Document" do
53
+ it "registers a save observer" do
54
+ root.should_receive(:register_save_observer)
55
+ proxy['new'] = item
56
+ end
57
+
58
+ it "sets the root" do
59
+ proxy['new'] = item
60
+ item._root.should == root
61
+ end
62
+ end
63
+ end
64
+
65
+ context "#merge!" do
66
+ context "when the key value is not a MongoDoc::Document" do
67
+
68
+ it "does not register a save observer" do
69
+ root.should_not_receive(:register_save_observer)
70
+ proxy.merge!(:new => other_item)
71
+ end
72
+
73
+ it "does not set the root" do
74
+ other_item.should_not_receive(:_root=)
75
+ proxy.merge!(:new => other_item)
76
+ end
77
+ end
78
+
79
+ context "when the key value is a MongoDoc::Document" do
80
+ it "registers a save observer" do
81
+ root.should_receive(:register_save_observer)
82
+ proxy.merge!(:new => item)
83
+ end
84
+
85
+ it "sets the root" do
86
+ proxy.merge!(:new => item)
87
+ item._root.should == root
88
+ end
89
+ end
90
+
91
+ context "with a block" do
92
+ it "calls into the block" do
93
+ proxy.merge!(:new => other_item) {|k, v1, v2| @result = v2}
94
+ @result.should == other_item
95
+ end
96
+
97
+ context "when the key value is not a MongoDoc::Document" do
98
+
99
+ it "does not register a save observer" do
100
+ root.should_not_receive(:register_save_observer)
101
+ proxy.merge!(:new => other_item) {|k, v1, v2| v2}
102
+ end
103
+
104
+ it "does not set the root" do
105
+ other_item.should_not_receive(:_root=)
106
+ proxy.merge!(:new => other_item) {|k, v1, v2| v2}
107
+ end
108
+ end
109
+
110
+ context "when the key value is a MongoDoc::Document" do
111
+ it "registers a save observer" do
112
+ root.should_receive(:register_save_observer)
113
+ proxy.merge!(:new => item) {|k, v1, v2| v2}
114
+ end
115
+
116
+ it "sets the root" do
117
+ proxy.merge!(:new => item) {|k, v1, v2| v2}
118
+ item._root.should == root
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ context "#replace" do
125
+ it "clears any existing data" do
126
+ proxy.should_receive(:clear)
127
+ proxy.replace(:new => other_item)
128
+ end
129
+
130
+ context "when the key value is not a MongoDoc::Document" do
131
+
132
+ it "does not register a save observer" do
133
+ root.should_not_receive(:register_save_observer)
134
+ proxy.replace(:new => other_item)
135
+ end
136
+
137
+ it "does not set the root" do
138
+ other_item.should_not_receive(:_root=)
139
+ proxy.replace(:new => other_item)
140
+ end
141
+ end
142
+
143
+ context "when the key value is a MongoDoc::Document" do
144
+ it "registers a save observer" do
145
+ root.should_receive(:register_save_observer)
146
+ proxy.replace(:new => item)
147
+ end
148
+
149
+ it "sets the root" do
150
+ proxy.replace(:new => item)
151
+ item._root.should == root
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ context "#build" do
158
+ it "builds an object of the collection class from the hash attrs" do
159
+ name = 'built'
160
+ proxy.build(:key, {:name => name}).name.should == name
161
+ end
162
+ end
163
+ end
@@ -66,7 +66,7 @@ describe "MongoDoc::Attributes" do
66
66
  class TestDoc
67
67
  include MongoDoc::Document
68
68
 
69
- has_one :subdoc
69
+ has_one :sub_doc
70
70
  end
71
71
 
72
72
  class SubDoc
@@ -75,39 +75,33 @@ describe "MongoDoc::Attributes" do
75
75
  key :data
76
76
  end
77
77
 
78
- it "sets the subdocuments parent to the parent proxy" do
79
- subdoc = SubDoc.new
80
- doc = TestDoc.new(:subdoc => subdoc)
81
- MongoDoc::ParentProxy.should === subdoc._parent
82
- subdoc._parent._parent.should == doc
78
+ let(:subdoc) { SubDoc.new }
79
+ let(:doc) { TestDoc.new(:sub_doc => subdoc) }
80
+
81
+ it "uses a proxy" do
82
+ MongoDoc::Associations::DocumentProxy.should === doc.sub_doc
83
83
  end
84
84
 
85
- it "set the subdocuments root" do
86
- subdoc = SubDoc.new
87
- middoc = TestDoc.new
88
- doc = TestDoc.new(:subdoc => middoc)
89
- middoc.subdoc = subdoc
90
- subdoc._root.should == doc
85
+ it "sets the subdocuments parent to the proxy" do
86
+ doc.sub_doc.should == subdoc._parent
91
87
  end
92
88
 
93
- it "sets the subdocuments root no matter how when it is inserted" do
94
- subdoc = SubDoc.new
95
- middoc = TestDoc.new(:subdoc => subdoc)
96
- doc = TestDoc.new(:subdoc => middoc)
97
- subdoc._root.should == doc
89
+ it "set the subdocuments root" do
90
+ doc.should == subdoc._root
98
91
  end
99
92
 
100
- class HasOneValidationTest
101
- include MongoDoc::Document
93
+ context "validations" do
94
+ class HasOneValidationTest
95
+ include MongoDoc::Document
102
96
 
103
- key :data
104
- validates_presence_of :data
105
- end
97
+ key :data
98
+ validates_presence_of :data
99
+ end
106
100
 
107
- it "cascades validations down" do
108
- invalid = HasOneValidationTest.new
109
- doc = TestDoc.new(:subdoc => invalid)
110
- doc.should have(1).error_on(:subdoc)
101
+ it "cascades validations down" do
102
+ invalid = HasOneValidationTest.new
103
+ TestDoc.new(:sub_doc => invalid).should have(1).error_on(:sub_doc)
104
+ end
111
105
  end
112
106
  end
113
107
 
@@ -144,50 +138,122 @@ describe "MongoDoc::Attributes" do
144
138
  has_many :sub_has_many_docs
145
139
  end
146
140
 
141
+ let(:subdoc) { SubHasManyDoc.new }
142
+ let(:doc) { TestHasManyDoc.new(:sub_docs => [subdoc]) }
143
+
147
144
  it "uses a proxy" do
148
- MongoDoc::Proxy.should === TestHasManyDoc.new.sub_docs
145
+ MongoDoc::Associations::CollectionProxy.should === TestHasManyDoc.new.sub_docs
149
146
  end
150
147
 
151
148
  it "sets the subdocuments parent to the proxy" do
152
- subdoc = SubHasManyDoc.new
153
- doc = TestHasManyDoc.new(:sub_docs => [subdoc])
154
- subdoc._parent.should == doc.sub_docs
149
+ doc.sub_docs.should == subdoc._parent
155
150
  end
156
151
 
157
152
  it "set the subdocuments root to the root" do
158
- subdoc = SubHasManyDoc.new
159
- doc = TestHasManyDoc.new(:sub_docs => [subdoc])
160
- subdoc._root.should == doc
153
+ doc.should == subdoc._root
161
154
  end
162
155
 
163
156
  it "uses the association name to find the children's class name" do
164
- subdoc = SubHasManyDoc.new
165
- doc = TestImplicitHasManyDoc.new(:sub_has_many_docs => [subdoc])
157
+ TestImplicitHasManyDoc.new.sub_has_many_docs.assoc_class.should == SubHasManyDoc
166
158
  end
167
159
 
168
- class HasManyValidationChild
160
+ context "validations" do
161
+ class HasManyValidationChild
162
+ include MongoDoc::Document
163
+
164
+ key :data
165
+ validates_presence_of :data
166
+ end
167
+
168
+ class HasManyValidationTest
169
+ include MongoDoc::Document
170
+
171
+ has_many :subdocs, :class_name => 'HasManyValidationChild'
172
+ end
173
+
174
+ let(:invalid_child) { HasHashValidationChild.new }
175
+ let(:doc) { HasHashValidationTest.new(:subdocs => {:key => invalid_child}) }
176
+
177
+ it "cascades validations and marks it in the parent" do
178
+ doc.should have(1).error_on(:subdocs)
179
+ end
180
+
181
+ it "cascades validations and marks it in the child" do
182
+ invalid_child.should have(1).error_on(:data)
183
+ end
184
+
185
+ it "ignores non-document children" do
186
+ HasManyValidationTest.new(:subdocs => ['not a doc']).should be_valid
187
+ end
188
+ end
189
+ end
190
+
191
+ context ".has_hash" do
192
+ class SubHasHashDoc
169
193
  include MongoDoc::Document
170
194
 
171
195
  key :data
172
- validates_presence_of :data
173
196
  end
174
197
 
175
- class HasManyValidationTest
198
+ class TestHasHashDoc
176
199
  include MongoDoc::Document
177
200
 
178
- has_many :subdocs, :class_name => 'HasManyValidationChild'
201
+ has_hash :sub_docs, :class_name => 'SubHasHashDoc'
179
202
  end
180
203
 
181
- it "cascades validations and marks it in the parent" do
182
- invalid = HasManyValidationChild.new
183
- doc = HasManyValidationTest.new(:subdocs => [invalid])
184
- doc.should have(1).error_on(:subdocs)
204
+ class TestImplicitHasHashDoc
205
+ include MongoDoc::Document
206
+
207
+ has_hash :sub_has_hash_docs
208
+ end
209
+
210
+ let(:subdoc) { SubHasHashDoc.new }
211
+ let(:doc) { TestHasHashDoc.new(:sub_docs => {:key => subdoc}) }
212
+
213
+ it "uses a proxy" do
214
+ MongoDoc::Associations::HashProxy.should === TestHasHashDoc.new.sub_docs
215
+ end
216
+
217
+ it "sets the subdocuments parent to the proxy" do
218
+ doc.sub_docs.should == subdoc._parent
219
+ end
220
+
221
+ it "set the subdocuments root to the root" do
222
+ doc.should == subdoc._root
223
+ end
224
+
225
+ it "uses the association name to find the children's class name" do
226
+ TestImplicitHasHashDoc.new.sub_has_hash_docs.assoc_class.should == SubHasHashDoc
185
227
  end
186
228
 
187
- it "cascades validations and marks it in the child" do
188
- invalid = HasManyValidationChild.new
189
- doc = HasManyValidationTest.new(:subdocs => [invalid])
190
- invalid.should have(1).error_on(:data)
229
+ context "validations" do
230
+ class HasHashValidationChild
231
+ include MongoDoc::Document
232
+
233
+ key :data
234
+ validates_presence_of :data
235
+ end
236
+
237
+ class HasHashValidationTest
238
+ include MongoDoc::Document
239
+
240
+ has_hash :subdocs, :class_name => 'HasHashValidationChild'
241
+ end
242
+
243
+ let(:invalid_child) { HasHashValidationChild.new }
244
+ let(:doc) { HasHashValidationTest.new(:subdocs => {:key => invalid_child}) }
245
+
246
+ it "cascades validations and marks it in the parent" do
247
+ doc.should have(1).error_on(:subdocs)
248
+ end
249
+
250
+ it "cascades validations and marks it in the child" do
251
+ invalid_child.should have(1).error_on(:data)
252
+ end
253
+
254
+ it "ignores non-document children" do
255
+ HasHashValidationTest.new(:subdocs => {:key => 'data'}).should be_valid
256
+ end
191
257
  end
192
258
  end
193
259
  end
@@ -21,7 +21,7 @@ describe "BSON for Mongo (BSON)" do
21
21
  MongoDoc::BSON.should_receive(:array_create).with(array, options)
22
22
  MongoDoc::BSON.decode(array, options)
23
23
  end
24
-
24
+
25
25
  it "returns the json value as is if the parameter is not a hash or array" do
26
26
  ["", 1, 1.5, true, false, nil].each do |type_value|
27
27
  MongoDoc::BSON.decode(type_value).should == type_value
@@ -37,7 +37,7 @@ describe "BSON for Mongo (BSON)" do
37
37
  MongoDoc::BSON.should_receive(:decode).with(first, options)
38
38
  MongoDoc::BSON.array_create(array, options)
39
39
  end
40
-
40
+
41
41
  it "just returns the array if the :raw_json option is used" do
42
42
  hash = {'key' => 'value', MongoDoc::BSON::CLASS_KEY => 'Date'}
43
43
  array = [hash]
@@ -45,32 +45,32 @@ describe "BSON for Mongo (BSON)" do
45
45
  MongoDoc::BSON.array_create(array, :raw_json => true).should == array
46
46
  end
47
47
  end
48
-
48
+
49
49
  describe "#bson_create" do
50
50
  it "leaves a simple hash intact" do
51
51
  hash = {}
52
52
  MongoDoc::BSON.bson_create(hash).should == hash
53
53
  end
54
-
54
+
55
55
  it "a class hash extracts the class, and calls class.bson_create" do
56
56
  base_hash = {'key' => 'value'}
57
57
  bson_hash = base_hash.merge(MongoDoc::BSON::CLASS_KEY => 'Date')
58
58
  Date.should_receive(:bson_create).with(base_hash, {})
59
59
  MongoDoc::BSON.bson_create(bson_hash)
60
60
  end
61
-
61
+
62
62
  it "ignores a class hash when the :raw_json option is used" do
63
63
  hash = {'key' => 'value', MongoDoc::BSON::CLASS_KEY => 'Date'}
64
64
  MongoDoc::BSON.bson_create(hash, :raw_json => true).should == hash
65
65
  end
66
66
  end
67
-
67
+
68
68
  describe "Hash" do
69
69
  it "#to_bson returns the hash" do
70
70
  hash = {'key' => 1}
71
71
  hash.to_bson.should == hash
72
72
  end
73
-
73
+
74
74
  it "#to_bson returns the hash with symbol keys as strings" do
75
75
  {:key => 1}.to_bson.should == {"key" => 1}
76
76
  end
@@ -79,45 +79,45 @@ describe "BSON for Mongo (BSON)" do
79
79
  hash = {'key' => 1}
80
80
  MongoDoc::BSON.decode(hash.to_bson).should == hash
81
81
  end
82
-
82
+
83
83
  it "decodes the values of the hash" do
84
84
  hash = {'key' => {'subkey' => Date.today}}
85
85
  MongoDoc::BSON.decode(hash.to_bson).should == hash
86
86
  end
87
87
  end
88
-
88
+
89
89
  describe "Array" do
90
90
  it "#to_bson returns the array" do
91
91
  array = ['string', 1]
92
92
  array.to_bson.should == array
93
93
  end
94
-
94
+
95
95
  it "#to_bson iterates over its elements" do
96
96
  array = []
97
97
  array.should_receive(:map)
98
98
  array.to_bson
99
99
  end
100
-
100
+
101
101
  it "decodes to an array" do
102
102
  array = ['string', 1]
103
103
  MongoDoc::BSON.decode(array.to_bson).should == array
104
104
  end
105
105
  end
106
-
106
+
107
107
  describe "Extensions to core classes" do
108
108
  it "#to_bson for objects that are BSON native return themselves" do
109
109
  [true, false, nil, 1.0, 1, /regexp/, 'string', :symbol, Time.now].each do |native|
110
110
  native.to_bson.should == native
111
111
  end
112
112
  end
113
-
113
+
114
114
  it "objects that are BSON native decode to themselves" do
115
115
  [true, false, nil, 1.0, 1, /regexp/, 'string', :symbol, Time.now].each do |native|
116
116
  hash = {'native' => native}
117
117
  MongoDoc::BSON.decode(hash.to_bson).should == hash
118
118
  end
119
119
  end
120
-
120
+
121
121
  it "Date#to_bson returns a date hash" do
122
122
  date = Date.today
123
123
  date.to_bson.should == {MongoDoc::BSON::CLASS_KEY => "Date", "dt" => date.strftime, "sg" => date.respond_to?(:start) ? date.start : date.sg}
@@ -127,40 +127,40 @@ describe "BSON for Mongo (BSON)" do
127
127
  date = Date.today
128
128
  MongoDoc::BSON.decode(date.to_bson).should == date
129
129
  end
130
-
130
+
131
131
  it "DateTime#to_bson returns a datetime hash" do
132
132
  datetime = DateTime.now
133
133
  datetime.to_bson.should == {MongoDoc::BSON::CLASS_KEY => "DateTime", "dt" => datetime.strftime, "sg" => datetime.respond_to?(:start) ? datetime.start : datetime.sg}
134
134
  end
135
-
135
+
136
136
  it "roundtrips DateTime" do
137
137
  datetime = DateTime.now
138
138
  MongoDoc::BSON.decode(datetime.to_bson).to_s.should == datetime.to_s
139
139
  end
140
140
  end
141
-
141
+
142
142
  describe "Mongo Classes" do
143
- [Mongo::ObjectID.new, Mongo::DBRef.new('ns', 1), Mongo::Code.new('code'), Mongo::Binary.new, Mongo::RegexpOfHolding.new('a', 'i', 'g')].each do |obj|
143
+ [Mongo::ObjectID.new, Mongo::DBRef.new('ns', 1), Mongo::Code.new('code'), Mongo::Binary.new].each do |obj|
144
144
  it "#to_bson for #{obj.class.name} returns self" do
145
145
  obj.to_bson.should == obj
146
146
  end
147
-
147
+
148
148
  it "objects of type #{obj.class.name} decode to themselves" do
149
149
  hash = {"mongo" => obj}
150
150
  MongoDoc::BSON.decode(hash.to_bson)["mongo"].should == obj
151
151
  end
152
152
  end
153
153
  end
154
-
154
+
155
155
  describe "Extensions to Object" do
156
156
  class Simple
157
157
  attr_accessor :value
158
158
  end
159
-
159
+
160
160
  class Complex
161
161
  attr_accessor :array_of_simple
162
162
  end
163
-
163
+
164
164
  before do
165
165
  @value1 = 'value1'
166
166
  @simple1 = Simple.new
@@ -175,7 +175,7 @@ describe "BSON for Mongo (BSON)" do
175
175
  it "renders a json representation of a simple object" do
176
176
  @simple1.to_bson.should be_bson_eql({MongoDoc::BSON::CLASS_KEY => Simple.name, "value" => @value1})
177
177
  end
178
-
178
+
179
179
  it "renders a json representation of an object with embedded objects" do
180
180
  @complex.to_bson.should be_bson_eql({MongoDoc::BSON::CLASS_KEY => Complex.name, "array_of_simple" => [@simple1.to_bson, @simple2.to_bson]})
181
181
  end
@@ -192,5 +192,5 @@ describe "BSON for Mongo (BSON)" do
192
192
  obj = MongoDoc::BSON.decode(@complex.to_bson)
193
193
  obj.array_of_simple.each {|o| o.should be_kind_of(Simple)}
194
194
  end
195
- end
195
+ end
196
196
  end