activecouch 0.1.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/MIT-LICENSE +20 -0
- data/README +42 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/lib/active_couch.rb +18 -0
- data/lib/active_couch/associations.rb +1 -0
- data/lib/active_couch/associations/has_many_association.rb +35 -0
- data/lib/active_couch/attribute.rb +46 -0
- data/lib/active_couch/base.rb +458 -0
- data/lib/active_couch/callbacks.rb +81 -0
- data/lib/active_couch/connection.rb +155 -0
- data/lib/active_couch/errors.rb +17 -0
- data/lib/active_couch/migrations.rb +3 -0
- data/lib/active_couch/migrations/errors.rb +4 -0
- data/lib/active_couch/migrations/migration.rb +77 -0
- data/lib/active_couch/migrations/migrator.rb +53 -0
- data/lib/active_couch/support.rb +2 -0
- data/lib/active_couch/support/extensions.rb +92 -0
- data/lib/active_couch/support/inflections.rb +52 -0
- data/lib/active_couch/support/inflector.rb +280 -0
- data/spec/attribute/initialize_spec.rb +138 -0
- data/spec/base/after_delete_spec.rb +107 -0
- data/spec/base/after_save_spec.rb +99 -0
- data/spec/base/before_delete_spec.rb +106 -0
- data/spec/base/before_save_spec.rb +98 -0
- data/spec/base/create_spec.rb +27 -0
- data/spec/base/database_spec.rb +65 -0
- data/spec/base/delete_spec.rb +78 -0
- data/spec/base/find_spec.rb +165 -0
- data/spec/base/from_json_spec.rb +48 -0
- data/spec/base/has_many_spec.rb +81 -0
- data/spec/base/has_spec.rb +76 -0
- data/spec/base/id_spec.rb +22 -0
- data/spec/base/initialize_spec.rb +43 -0
- data/spec/base/module_spec.rb +18 -0
- data/spec/base/nested_class_spec.rb +19 -0
- data/spec/base/rev_spec.rb +16 -0
- data/spec/base/save_spec.rb +65 -0
- data/spec/base/site_spec.rb +41 -0
- data/spec/base/to_json_spec.rb +64 -0
- data/spec/connection/initialize_spec.rb +28 -0
- data/spec/has_many_association/initialize_spec.rb +33 -0
- data/spec/migration/define_spec.rb +29 -0
- data/spec/migration/include_attributes_spec.rb +30 -0
- data/spec/migration/view_js_spec.rb +46 -0
- data/spec/migration/with_filter_spec.rb +13 -0
- data/spec/migration/with_key_spec.rb +13 -0
- data/spec/migrator/create_database_spec.rb +48 -0
- data/spec/migrator/delete_database_spec.rb +46 -0
- data/spec/migrator/migrate_spec.rb +99 -0
- data/spec/spec_helper.rb +9 -0
- metadata +104 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "ActiveCouch::Base #delete instance-level method" do
|
4
|
+
before(:each) do
|
5
|
+
class Person < ActiveCouch::Base
|
6
|
+
site 'http://localhost:5984/'
|
7
|
+
has :name
|
8
|
+
end
|
9
|
+
ActiveCouch::Migrator.create_database('http://localhost:5984/', 'people')
|
10
|
+
@person = Person.create(:name => 'McLovin')
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ActiveCouch::Migrator.delete_database('http://localhost:5984/', 'people')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have an instance method called delete" do
|
18
|
+
@person.methods.include?('delete').should == true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be able to delete itself from the CouchDB database and return true" do
|
22
|
+
@person.delete.should == true
|
23
|
+
@person.id.should == nil
|
24
|
+
@person.rev.should == nil
|
25
|
+
# Check whether document has actually been deleted
|
26
|
+
response = Net::HTTP.get_response URI.parse("http://localhost:5984/people/_all_docs/")
|
27
|
+
response.body.index('"total_rows":0').should_not == nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should raise an error if the revision for the object is not set and is attempted to be deleted" do
|
31
|
+
p = Person.new(:name => 'McLovin')
|
32
|
+
lambda { p.delete }.should raise_error(ArgumentError, "You must specify a revision for the document to be deleted")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should raise an error if the id for the object is not set, but the revision is set and is attempted to be deleted" do
|
36
|
+
p = Person.new(:name => 'McLovin')
|
37
|
+
p.rev = '123'
|
38
|
+
lambda { p.delete }.should raise_error(ArgumentError, "You must specify an ID for the document to be deleted")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "ActiveCouch::Base #delete class-level method" do
|
43
|
+
before(:each) do
|
44
|
+
class Person < ActiveCouch::Base
|
45
|
+
site 'http://localhost:5984/'
|
46
|
+
has :name
|
47
|
+
end
|
48
|
+
ActiveCouch::Migrator.create_database('http://localhost:5984/', 'people')
|
49
|
+
@person = Person.create(:name => 'McLovin')
|
50
|
+
end
|
51
|
+
|
52
|
+
after(:each) do
|
53
|
+
ActiveCouch::Migrator.delete_database('http://localhost:5984/', 'people')
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should have a class method called delete" do
|
57
|
+
Person.methods.include?('delete').should == true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be able to delete a CouchDB document and return true after successful deletion" do
|
61
|
+
Person.delete(:id => @person.id, :rev => @person.rev).should == true
|
62
|
+
# Check whether document has actually been deleted
|
63
|
+
response = Net::HTTP.get_response URI.parse("http://localhost:5984/people/_all_docs/")
|
64
|
+
response.body.index('"total_rows":0').should_not == nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should raise an error if the id is not specified in the options hash" do
|
68
|
+
lambda { Person.delete(:rev => 'abc') }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should raise an error if the rev is not specified in the options hash" do
|
72
|
+
lambda { Person.delete(:id => 'abc') }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise an error if a nil object is passed as a param to delete" do
|
76
|
+
lambda { Person.delete(nil) }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "ActiveCouch::Base #find method with just simple attributes" do
|
4
|
+
before(:each) do
|
5
|
+
# Define the model
|
6
|
+
class Person < ActiveCouch::Base
|
7
|
+
site 'http://localhost:5984'
|
8
|
+
has :name
|
9
|
+
end
|
10
|
+
# Define the migration
|
11
|
+
class ByName < ActiveCouch::Migration
|
12
|
+
define :for_db => 'people' do
|
13
|
+
with_key 'name'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
# Create the database first
|
17
|
+
ActiveCouch::Migrator.create_database('http://localhost:5984', 'people')
|
18
|
+
# Create a view
|
19
|
+
ActiveCouch::Migrator.migrate('http://localhost:5984', ByName)
|
20
|
+
# Save an object
|
21
|
+
Person.new(:name => 'McLovin').save
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:each) do
|
25
|
+
# Delete the database last
|
26
|
+
ActiveCouch::Migrator.delete_database('http://localhost:5984', 'people')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should respond to the find method" do
|
30
|
+
Person.should respond_to(:find)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return an array with one Person object in it, when sent method find with parameter :all" do
|
34
|
+
people = Person.find(:all, :params => {:name => 'McLovin'})
|
35
|
+
people.class.should == Array
|
36
|
+
# Size of people
|
37
|
+
people.size.should == 1
|
38
|
+
|
39
|
+
people.first.class.should == Person
|
40
|
+
people.first.name.should == 'McLovin'
|
41
|
+
# Check if id and rev are set
|
42
|
+
people.first.id.should_not == nil
|
43
|
+
people.first.rev.should_not == nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return one Person object when sent method find with parameter :one" do
|
47
|
+
person = Person.find(:first, :params => {:name => 'McLovin'})
|
48
|
+
person.class.should == Person
|
49
|
+
person.name.should == 'McLovin'
|
50
|
+
# Check if id and rev are set
|
51
|
+
person.id.should_not == nil
|
52
|
+
person.rev.should_not == nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return an empty array when sent method find with parameter :all and is not able to find any" do
|
56
|
+
people = Person.find(:all, :params => {:name => 'Seth'})
|
57
|
+
people.class.should == Array
|
58
|
+
people.size.should == 0
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return a nil object when sent method find with parameter :first and is not able to find any" do
|
62
|
+
person = Person.find(:first, :params => {:name => 'Seth'})
|
63
|
+
person.should == nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "ActiveCouch::Base #find method with multiple documents in the CouchDB database" do
|
68
|
+
before(:each) do
|
69
|
+
class Person < ActiveCouch::Base
|
70
|
+
site 'http://localhost:5984'
|
71
|
+
|
72
|
+
has :first_name
|
73
|
+
has :last_name
|
74
|
+
end
|
75
|
+
|
76
|
+
# Define the migration
|
77
|
+
class ByLastName < ActiveCouch::Migration
|
78
|
+
define :for_db => 'people' do
|
79
|
+
with_key 'last_name'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# Create the database first
|
83
|
+
ActiveCouch::Migrator.create_database('http://localhost:5984', 'people')
|
84
|
+
# Create a view
|
85
|
+
ActiveCouch::Migrator.migrate('http://localhost:5984', ByLastName)
|
86
|
+
# Save two objects
|
87
|
+
Person.create(:last_name => 'McLovin', :first_name => 'Seth')
|
88
|
+
Person.create(:last_name => 'McLovin', :first_name => 'Bob')
|
89
|
+
end
|
90
|
+
|
91
|
+
after(:each) do
|
92
|
+
# Delete the database last
|
93
|
+
ActiveCouch::Migrator.delete_database('http://localhost:5984', 'people')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should find all objects in the database when find method is sent the param :all" do
|
97
|
+
people = Person.find(:all, :params => {:last_name => 'McLovin'})
|
98
|
+
# Check if it is an array and if the size is 2
|
99
|
+
people.class.should == Array
|
100
|
+
people.size.should == 2
|
101
|
+
# The id's and rev's for all the objects must not be nil
|
102
|
+
people.each do |p|
|
103
|
+
p.id.should_not == nil
|
104
|
+
p.rev.should_not == nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should find only the first object in the database when find method is sent with the param :first" do
|
109
|
+
people = Person.find(:first, :params => {:last_name => 'McLovin'})
|
110
|
+
# Check if this is a Person and if the size is 1
|
111
|
+
people.class.should == Person
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "ActiveCouch::Base #find method with an object which has associations" do
|
116
|
+
before(:each) do
|
117
|
+
class Comment < ActiveCouch::Base
|
118
|
+
site 'http://localhost:5984'
|
119
|
+
has :body
|
120
|
+
end
|
121
|
+
|
122
|
+
class Blog < ActiveCouch::Base
|
123
|
+
site 'http://localhost:5984'
|
124
|
+
has :title
|
125
|
+
has_many :comments
|
126
|
+
end
|
127
|
+
|
128
|
+
# Define the migration
|
129
|
+
class ByTitle < ActiveCouch::Migration
|
130
|
+
define :for_db => 'blogs' do
|
131
|
+
with_key 'title'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Create the database first
|
136
|
+
ActiveCouch::Migrator.create_database('http://localhost:5984', 'blogs')
|
137
|
+
# Create a view
|
138
|
+
ActiveCouch::Migrator.migrate('http://localhost:5984', ByTitle)
|
139
|
+
blog = Blog.new(:title => 'iPhone in Singapore')
|
140
|
+
# Associations
|
141
|
+
blog.add_comment(Comment.new(:body => 'soon plz'))
|
142
|
+
blog.add_comment(Comment.new(:body => 'ya rly!'))
|
143
|
+
# Save the blog
|
144
|
+
blog.save
|
145
|
+
end
|
146
|
+
|
147
|
+
after(:each) do
|
148
|
+
# Create the database first
|
149
|
+
ActiveCouch::Migrator.delete_database('http://localhost:5984', 'blogs')
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should be able to retrieve the simple attributes" do
|
153
|
+
blog = Blog.find(:first, :params => {:title => 'iPhone in Singapore'})
|
154
|
+
blog.title.should == 'iPhone in Singapore'
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should be able to retrieve associations" do
|
158
|
+
blog = Blog.find(:first, :params => {:title => 'iPhone in Singapore'})
|
159
|
+
blog.comments.size.should == 2
|
160
|
+
# Check whether the bodies of the comments exist
|
161
|
+
(blog.comments.inspect =~ /soon plz/).should_not == nil
|
162
|
+
(blog.comments.inspect =~ /ya rly!/).should_not == nil
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "ActiveCouch::Base #from_json method, with many attributes" do
|
4
|
+
before(:each) do
|
5
|
+
class Hotel < ActiveCouch::Base
|
6
|
+
has :name, :which_is => :text, :with_default_value => "Swissotel The Stamford"
|
7
|
+
has :star_rating, :which_is => :decimal, :with_default_value => 5.0
|
8
|
+
has :rooms, :which_is => :number, :with_default_value => 100
|
9
|
+
end
|
10
|
+
|
11
|
+
class Hospital < ActiveCouch::Base
|
12
|
+
has :name
|
13
|
+
end
|
14
|
+
|
15
|
+
class CrazyPerson < ActiveCouch::Base
|
16
|
+
has :name, :which_is => :text, :with_default_value => "Crazed McLovin"
|
17
|
+
has_many :hospitals
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have the from_json method" do
|
22
|
+
Hotel.should respond_to(:from_json)
|
23
|
+
Hospital.should respond_to(:from_json)
|
24
|
+
CrazyPerson.should respond_to(:from_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should instantiate an object when sent the from_json method with valid json as a parameter" do
|
28
|
+
h = Hotel.from_json("{\"name\":\"Swissotel The Stamford\",\"rooms\":200,\"star_rating\":4.0}")
|
29
|
+
h.class.should == Hotel
|
30
|
+
# Check whether all attributes are set correctly
|
31
|
+
h.name.should == "Swissotel The Stamford"
|
32
|
+
h.rooms.should == 200
|
33
|
+
h.star_rating.should == 4.0
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should instantiate an object when sent the from_json method with valid JSON (containing associations) as a parameter" do
|
37
|
+
crazy = CrazyPerson.from_json('{"name":"Crazed McLovin","hospitals":[{"name":"Crazy Hospital 1"},{"name":"Crazy Hospital 2"}]}')
|
38
|
+
|
39
|
+
crazy.name == "Crazed McLovin"
|
40
|
+
crazy.hospitals.size.should == 2
|
41
|
+
|
42
|
+
hospitals = crazy.hospitals.collect{|h| h.name }
|
43
|
+
hospitals.sort!
|
44
|
+
|
45
|
+
hospitals.first.should == 'Crazy Hospital 1'
|
46
|
+
hospitals.last.should == 'Crazy Hospital 2'
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "A class which is a subclass of ActiveCouch::Base with a has_many association" do
|
4
|
+
before(:each) do
|
5
|
+
class Person < ActiveCouch::Base
|
6
|
+
has :name, :which_is => :text
|
7
|
+
end
|
8
|
+
|
9
|
+
class AgedPerson < ActiveCouch::Base
|
10
|
+
has :name
|
11
|
+
has :age, :which_is => :number, :with_default_value => 10
|
12
|
+
end
|
13
|
+
|
14
|
+
class Contact < ActiveCouch::Base
|
15
|
+
has_many :people
|
16
|
+
end
|
17
|
+
|
18
|
+
@c = Contact.new
|
19
|
+
@p1 = Person.new
|
20
|
+
@a1 = AgedPerson.new
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have an instance variable called associations which is a Hash with the key being :people" do
|
24
|
+
Contact.associations.class.should == Hash
|
25
|
+
Contact.associations.keys.should == [:people]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have methods called people and add_person" do
|
29
|
+
@c.should respond_to(:people)
|
30
|
+
@c.should respond_to(:add_person)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a method called people which returns an empty array" do
|
34
|
+
@c.people.should == []
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to add a Person object to the association" do
|
38
|
+
@c.add_person(@p1)
|
39
|
+
@c.people.should == [@p1]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should raise an error when trying to add an object which is not of the association's type" do
|
43
|
+
lambda{ @c.add_person(@a1) }.should raise_error(ActiveCouch::InvalidCouchTypeError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "An object instantiated from class which is a subclass of ActiveCouch::Base" do
|
48
|
+
before(:each) do
|
49
|
+
class Comment < ActiveCouch::Base
|
50
|
+
has :body
|
51
|
+
end
|
52
|
+
|
53
|
+
class Blog < ActiveCouch::Base
|
54
|
+
has :title
|
55
|
+
has_many :comments
|
56
|
+
end
|
57
|
+
|
58
|
+
@comment1 = Comment.new(:body => "I can haz redbull?")
|
59
|
+
@comment2 = Comment.new(:body => 'k thx bai')
|
60
|
+
@blog = Blog.new(:title => 'Lolcats Primer', :comments => [@comment1, @comment2])
|
61
|
+
@blog1 = Blog.new(:title => 'Lolcats Primer The Sequel', :comments => [{:body => 'can'}, {:body => 'haz'}])
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be able to initialize with a hash which contains descendents of ActiveCouch::Base" do
|
65
|
+
@comment1.body.should == "I can haz redbull?"
|
66
|
+
@comment2.body.should == "k thx bai"
|
67
|
+
|
68
|
+
@blog.title.should == 'Lolcats Primer'
|
69
|
+
@blog.comments.should == [@comment1, @comment2]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to initialize from a hash which contains only Strings" do
|
73
|
+
@blog1.title.should == 'Lolcats Primer The Sequel'
|
74
|
+
|
75
|
+
comment_bodies = @blog1.comments.collect{|c| c.body }
|
76
|
+
comment_bodies.sort!
|
77
|
+
|
78
|
+
comment_bodies.first.should == 'can'
|
79
|
+
comment_bodies.last.should == 'haz'
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "A class which is a subclass of ActiveCouch::Base" do
|
4
|
+
before(:each) do
|
5
|
+
class Person < ActiveCouch::Base
|
6
|
+
has :name, :which_is => :text
|
7
|
+
end
|
8
|
+
|
9
|
+
@p = Person.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have a method called name which returns the value of the variable name" do
|
13
|
+
@p.should respond_to(:name)
|
14
|
+
@p.name.should == ""
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have a method called name= which should let you set the instance variable name" do
|
18
|
+
@p.should respond_to(:name=)
|
19
|
+
@p.name = "McLovin"
|
20
|
+
@p.name.should == "McLovin"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "A class which is a subclass of ActiveCouch::Base with a default value specified" do
|
25
|
+
before(:each) do
|
26
|
+
class NamedPerson < ActiveCouch::Base
|
27
|
+
has :name, :which_is => :text, :with_default_value => "McLovin"
|
28
|
+
end
|
29
|
+
|
30
|
+
@n = NamedPerson.new
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a method called name which returns the value of the variable name" do
|
34
|
+
@n.should respond_to(:name)
|
35
|
+
@n.name.should == "McLovin"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have a method called name= which should let you set the instance variable name" do
|
39
|
+
@n.should respond_to(:name=)
|
40
|
+
@n.name = "Seth"
|
41
|
+
@n.name.should == "Seth"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "A class which is a subclass of ActiveCouch::Base with a default numerical value specified" do
|
46
|
+
before(:each) do
|
47
|
+
class AgedPerson < ActiveCouch::Base
|
48
|
+
has :name
|
49
|
+
has :age, :which_is => :number, :with_default_value => 10
|
50
|
+
end
|
51
|
+
|
52
|
+
@a = AgedPerson.new
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should have an instance variable called attributes which is a Hash with the keys being :name, :age" do
|
56
|
+
AgedPerson.attributes.class.should == Hash
|
57
|
+
AgedPerson.attributes.keys.index(:name).should_not == nil
|
58
|
+
AgedPerson.attributes.keys.index(:age).should_not == nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should have methods called name and age which return the values of the variables name and age respectively" do
|
62
|
+
@a.should respond_to(:name)
|
63
|
+
@a.should respond_to(:age)
|
64
|
+
|
65
|
+
@a.name.should == ""
|
66
|
+
@a.age.should == 10
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have a method called name= which should let you set the instance variable name" do
|
70
|
+
@a.should respond_to(:name=)
|
71
|
+
@a.should respond_to(:age=)
|
72
|
+
|
73
|
+
@a.age = 15
|
74
|
+
@a.age.should == 15
|
75
|
+
end
|
76
|
+
end
|