couchbase-jruby-model 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +155 -0
- data/Rakefile +22 -0
- data/couchbase-jruby-model.gemspec +27 -0
- data/lib/couchbase-jruby-model.rb +23 -0
- data/lib/couchbase/active_model.rb +69 -0
- data/lib/couchbase/model.rb +859 -0
- data/lib/couchbase/model/configuration.rb +30 -0
- data/lib/couchbase/model/ext/camelize.rb +23 -0
- data/lib/couchbase/model/ext/constantize.rb +29 -0
- data/lib/couchbase/model/ext/singleton_class.rb +24 -0
- data/lib/couchbase/model/uuid.rb +113 -0
- data/lib/couchbase/model/version.rb +26 -0
- data/lib/couchbase/railtie.rb +142 -0
- data/lib/rails/generators/couchbase/config/config_generator.rb +43 -0
- data/lib/rails/generators/couchbase/config/templates/couchbase.yml +23 -0
- data/lib/rails/generators/couchbase/view/templates/map.js +40 -0
- data/lib/rails/generators/couchbase/view/templates/reduce.js +61 -0
- data/lib/rails/generators/couchbase/view/view_generator.rb +43 -0
- data/lib/rails/generators/couchbase_generator.rb +42 -0
- data/tasks/package.rake +27 -0
- data/tasks/test.rake +34 -0
- data/tasks/util.rake +21 -0
- data/test/setup.rb +168 -0
- data/test/test_active_model_integration.rb +124 -0
- data/test/test_model.rb +311 -0
- data/test/test_model_rails_integration.rb +76 -0
- data/test/test_uuid.rb +32 -0
- metadata +151 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
|
20
|
+
class ActiveUser < Couchbase::Model
|
21
|
+
attribute :name
|
22
|
+
attribute :email
|
23
|
+
attribute :role
|
24
|
+
attribute :created_at, :updated_at, :default => lambda { Time.now.utc }
|
25
|
+
|
26
|
+
validates_presence_of :email
|
27
|
+
validates :role, :presence => true, :inclusion => { :in => %w(admin editor) }
|
28
|
+
|
29
|
+
before_create :upcase_name
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def upcase_name
|
34
|
+
self.name = self.name.upcase unless self.name.nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ActiveObj < Couchbase::Model
|
39
|
+
end
|
40
|
+
|
41
|
+
class TestActiveModelIntegration < MiniTest::Unit::TestCase
|
42
|
+
|
43
|
+
include ActiveModel::Lint::Tests
|
44
|
+
|
45
|
+
def setup
|
46
|
+
@model = ActiveUser.new # used by ActiveModel::Lint::Tests
|
47
|
+
@mock = start_mock
|
48
|
+
bucket = Couchbase.connect(:hostname => @mock.host, :port => @mock.port)
|
49
|
+
ActiveObj.bucket = ActiveUser.bucket = bucket
|
50
|
+
end
|
51
|
+
|
52
|
+
def teardown
|
53
|
+
stop_mock(@mock)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_active_model_includes
|
57
|
+
[
|
58
|
+
ActiveModel::Conversion,
|
59
|
+
ActiveModel::Validations,
|
60
|
+
ActiveModel::Validations::Callbacks,
|
61
|
+
ActiveModel::Validations::HelperMethods
|
62
|
+
].each do |mod|
|
63
|
+
assert ActiveUser.ancestors.include?(mod), "Model not including #{mod}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_callbacks
|
68
|
+
[
|
69
|
+
:before_validation, :after_validation,
|
70
|
+
:after_initialize, :before_create, :around_create,
|
71
|
+
:after_create, :before_delete, :around_delete,
|
72
|
+
:after_delete, :before_save, :around_save, :after_save,
|
73
|
+
:before_update, :around_update, :after_update
|
74
|
+
].each do |callback|
|
75
|
+
assert ActiveObj.respond_to?(callback), "Model doesn't support callback: #{callback}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_active_model_validations
|
80
|
+
no_role = ActiveUser.new(:email => 'joe@example.com', :role => nil)
|
81
|
+
bad_role = ActiveUser.new(:email => 'joe@example.com', :role => 'bad')
|
82
|
+
good_role = ActiveUser.new(:email => 'joe@example.com', :role => 'admin')
|
83
|
+
|
84
|
+
refute no_role.valid?
|
85
|
+
refute bad_role.valid?
|
86
|
+
assert good_role.valid?
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_active_model_validation_helpers
|
90
|
+
valid = ActiveUser.new(:email => 'joe@example.com', :role => 'editor')
|
91
|
+
invalid = ActiveUser.new(:name => 'Joe', :role => 'editor')
|
92
|
+
|
93
|
+
assert valid.valid?
|
94
|
+
refute invalid.valid?
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_before_save_callback
|
98
|
+
assert user = ActiveUser.create(:name => 'joe', :role => 'admin', :email => 'joe@example.com')
|
99
|
+
assert_equal 'JOE', user.name
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_model_name_exposes_singular_and_human_name
|
103
|
+
assert_equal 'active_user', @model.class.model_name.singular
|
104
|
+
assert_equal 'Active user', @model.class.model_name.human
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_model_equality
|
108
|
+
obj1 = ActiveObj.create
|
109
|
+
obj2 = ActiveObj.find(obj1.id)
|
110
|
+
|
111
|
+
assert_equal obj1, obj2
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_to_key
|
115
|
+
assert_equal ['the-id'], ActiveObj.new(:id => 'the-id').to_key
|
116
|
+
assert_equal ['the-key'], ActiveObj.new(:key => 'the-key').to_key
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_to_param
|
120
|
+
assert_equal 'the-id', ActiveObj.new(:id => 'the-id').to_param
|
121
|
+
assert_equal 'the-key', ActiveObj.new(:key => ['the', 'key']).to_param
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
data/test/test_model.rb
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
|
20
|
+
class Post < Couchbase::Model
|
21
|
+
attribute :title
|
22
|
+
attribute :body
|
23
|
+
attribute :author, :default => 'Anonymous'
|
24
|
+
attribute :created_at, :default => lambda { Time.utc('2010-01-01') }
|
25
|
+
end
|
26
|
+
|
27
|
+
class ValidPost < Couchbase::Model
|
28
|
+
attribute :title
|
29
|
+
|
30
|
+
def valid?
|
31
|
+
title && !title.empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Brewery < Couchbase::Model
|
36
|
+
attribute :name
|
37
|
+
end
|
38
|
+
|
39
|
+
class Beer < Couchbase::Model
|
40
|
+
attribute :name
|
41
|
+
belongs_to :brewery
|
42
|
+
end
|
43
|
+
|
44
|
+
class Attachment < Couchbase::Model
|
45
|
+
defaults :format => :plain
|
46
|
+
end
|
47
|
+
|
48
|
+
class Comments < Couchbase::Model
|
49
|
+
include Enumerable
|
50
|
+
attribute :comments, :default => []
|
51
|
+
end
|
52
|
+
|
53
|
+
class User < Couchbase::Model
|
54
|
+
design_document :people
|
55
|
+
end
|
56
|
+
|
57
|
+
class TestModel < MiniTest::Unit::TestCase
|
58
|
+
|
59
|
+
def setup
|
60
|
+
@mock = start_mock
|
61
|
+
bucket = Couchbase.connect(:hostname => @mock.host, :port => @mock.port)
|
62
|
+
[Post, ValidPost, Brewery, Beer, Attachment].each do |model|
|
63
|
+
model.bucket = bucket
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def teardown
|
68
|
+
stop_mock(@mock)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_design_document
|
72
|
+
assert_equal 'people', User.design_document
|
73
|
+
assert_equal 'new_people', User.design_document('new_people')
|
74
|
+
assert_equal 'post', Post.design_document
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_it_supports_value_property
|
78
|
+
doc = {
|
79
|
+
'id' => 'x',
|
80
|
+
'key' => 'x',
|
81
|
+
'value' => 'x',
|
82
|
+
'doc' => {
|
83
|
+
'value' => {'title' => 'foo'}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
post = Post.wrap(Post.bucket, doc)
|
87
|
+
assert_equal 'foo', post.title
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_it_supports_json_property
|
91
|
+
doc = {
|
92
|
+
'id' => 'x',
|
93
|
+
'key' => 'x',
|
94
|
+
'value' => 'x',
|
95
|
+
'doc' => {
|
96
|
+
'json' => {'title' => 'foo'}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
post = Post.wrap(Post.bucket, doc)
|
100
|
+
assert_equal 'foo', post.title
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_assigns_attributes_from_the_hash
|
104
|
+
post = Post.new(:title => 'Hello, world')
|
105
|
+
assert_equal 'Hello, world', post.title
|
106
|
+
refute post.body
|
107
|
+
refute post.id
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_uses_default_value_or_nil
|
111
|
+
post = Post.new(:title => 'Hello, world')
|
112
|
+
refute post.body
|
113
|
+
assert_equal 'Anonymous', post.author
|
114
|
+
assert_equal 'Anonymous', post.attributes[:author]
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_allows_lambda_as_default_value
|
118
|
+
post = Post.new(:title => 'Hello, world')
|
119
|
+
expected = Time.utc('2010-01-01')
|
120
|
+
assert_equal expected, post.created_at
|
121
|
+
assert_equal expected, post.attributes[:created_at]
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_assings_id_and_saves_the_object
|
125
|
+
post = Post.create(:title => 'Hello, world')
|
126
|
+
assert post.id
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_updates_attributes
|
130
|
+
post = Post.create(:title => 'Hello, world')
|
131
|
+
post.update(:body => 'This is my first example')
|
132
|
+
assert_equal 'This is my first example', post.body
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_refreshes_the_attributes_with_reload_method
|
136
|
+
orig = Post.create(:title => 'Hello, world')
|
137
|
+
double = Post.find(orig.id)
|
138
|
+
double.update(:title => 'Good bye, world')
|
139
|
+
orig.reload
|
140
|
+
assert_equal 'Good bye, world', orig.title
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_reloads_cas_value_with_reload_method
|
144
|
+
orig = Post.create(:title => "Hello, world")
|
145
|
+
double = Post.find(orig.id)
|
146
|
+
orig.update(:title => "Good bye, world")
|
147
|
+
double.reload
|
148
|
+
|
149
|
+
assert_equal orig.meta[:cas], double.meta[:cas]
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_it_raises_not_found_exception
|
153
|
+
assert_raises Couchbase::Error::NotFound do
|
154
|
+
Post.find('missing_key')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_it_returns_nil_when_key_not_found
|
159
|
+
refute Post.find_by_id('missing_key')
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_doesnt_raise_if_the_attribute_redefined
|
163
|
+
eval <<-EOC
|
164
|
+
class RefinedPost < Couchbase::Model
|
165
|
+
attribute :title
|
166
|
+
attribute :title
|
167
|
+
end
|
168
|
+
EOC
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_allows_to_define_several_attributes_at_once
|
172
|
+
eval <<-EOC
|
173
|
+
class Comment < Couchbase::Model
|
174
|
+
attribute :name, :email, :body
|
175
|
+
end
|
176
|
+
EOC
|
177
|
+
|
178
|
+
comment = Comment.new
|
179
|
+
assert_respond_to comment, :name
|
180
|
+
assert_respond_to comment, :email
|
181
|
+
assert_respond_to comment, :body
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_allows_arbitrary_ids
|
185
|
+
Post.create(:id => uniq_id, :title => 'Foo')
|
186
|
+
assert_equal 'Foo', Post.find(uniq_id).title
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_returns_an_instance_of_post
|
190
|
+
Post.bucket.set(uniq_id, {:title => 'foo'})
|
191
|
+
assert Post.find(uniq_id).kind_of?(Post)
|
192
|
+
assert_equal uniq_id, Post.find(uniq_id).id
|
193
|
+
assert_equal 'foo', Post.find(uniq_id).title
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_changes_its_attributes
|
197
|
+
post = Post.create(:title => 'Hello, world')
|
198
|
+
post.title = 'Good bye, world'
|
199
|
+
post.save.reload
|
200
|
+
assert_equal 'Good bye, world', post.title
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_assings_a_new_id_to_each_record
|
204
|
+
post1 = Post.create
|
205
|
+
post2 = Post.create
|
206
|
+
|
207
|
+
refute post1.new?
|
208
|
+
refute post2.new?
|
209
|
+
refute_equal post1.id, post2.id
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_deletes_an_existent_model
|
213
|
+
post = Post.create(:id => uniq_id)
|
214
|
+
assert post.delete
|
215
|
+
assert_raises Couchbase::Error::NotFound do
|
216
|
+
Post.bucket.get(uniq_id)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_fails_to_delete_model_without_id
|
221
|
+
post = Post.new(:title => 'Hello')
|
222
|
+
refute post.id
|
223
|
+
assert_raises Couchbase::Error::MissingId do
|
224
|
+
post.delete
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_belongs_to_assoc
|
229
|
+
brewery = Brewery.create(:name => 'Anheuser-Busch')
|
230
|
+
assert_includes Beer.attributes.keys, :brewery_id
|
231
|
+
beer = Beer.create(:name => 'Budweiser', :brewery_id => brewery.id)
|
232
|
+
assert_respond_to beer, :brewery
|
233
|
+
assoc = beer.brewery
|
234
|
+
assert_instance_of Brewery, assoc
|
235
|
+
assert_equal 'Anheuser-Busch', assoc.name
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_to_key
|
239
|
+
assert_equal ['the-id'], Post.new(:id => 'the-id').to_key
|
240
|
+
assert_equal ['the-key'], Post.new(:key => 'the-key').to_key
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_to_param
|
244
|
+
assert_equal 'the-id', Post.new(:id => 'the-id').to_param
|
245
|
+
assert_equal 'the-key', Post.new(:key => ['the', 'key']).to_param
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_as_json
|
249
|
+
require 'active_support/json/encoding'
|
250
|
+
|
251
|
+
response = {'id' => 'the-id'}
|
252
|
+
assert_equal response, Post.new(:id => 'the-id').as_json
|
253
|
+
|
254
|
+
response = {}
|
255
|
+
assert_equal response, Post.new(:id => 'the-id').as_json(:except => :id)
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_validation
|
259
|
+
post = ValidPost.create(:title => 'Hello, World!')
|
260
|
+
assert post.valid?, 'post with title should be valid'
|
261
|
+
post.title = nil
|
262
|
+
refute post.save
|
263
|
+
assert_raises(Couchbase::Error::RecordInvalid) do
|
264
|
+
post.save!
|
265
|
+
end
|
266
|
+
refute ValidPost.create(:title => nil)
|
267
|
+
assert_raises(Couchbase::Error::RecordInvalid) do
|
268
|
+
ValidPost.create!(:title => nil)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_blob_documents
|
273
|
+
contents = File.read(__FILE__)
|
274
|
+
id = Attachment.create(:raw => contents).id
|
275
|
+
blob = Attachment.find(id)
|
276
|
+
assert_equal contents, blob.raw
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_couchbase_ancestor
|
280
|
+
assert_equal Couchbase::Model, Comments.couchbase_ancestor
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_returns_multiple_instances_of_post
|
284
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
285
|
+
Post.create(:id => uniq_id('second'), :title => 'bar')
|
286
|
+
|
287
|
+
results = Post.find([uniq_id('first'), uniq_id('second')])
|
288
|
+
assert results.kind_of?(Array)
|
289
|
+
assert results.size == 2
|
290
|
+
assert results.detect { |post| post.id == uniq_id('first') }.title == 'foo'
|
291
|
+
assert results.detect { |post| post.id == uniq_id('second') }.title == 'bar'
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_returns_array_for_array_of_ids
|
295
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
296
|
+
|
297
|
+
results = Post.find([uniq_id('first')])
|
298
|
+
assert results.kind_of?(Array)
|
299
|
+
assert results.size == 1
|
300
|
+
assert results[0].title == 'foo'
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_returns_array_for_array_of_ids_using_find_by_id
|
304
|
+
Post.create(:id => uniq_id('first'), :title => 'foo')
|
305
|
+
|
306
|
+
results = Post.find_by_id([uniq_id('first')])
|
307
|
+
assert results.kind_of?(Array)
|
308
|
+
assert results.size == 1
|
309
|
+
assert results[0].title == 'foo'
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
|
20
|
+
class Program < Couchbase::Model
|
21
|
+
attribute :title
|
22
|
+
attribute :genres, :default => []
|
23
|
+
end
|
24
|
+
|
25
|
+
class Movie < Program
|
26
|
+
attribute :mpaa_rating
|
27
|
+
attribute :runtime
|
28
|
+
end
|
29
|
+
|
30
|
+
class Series < Program
|
31
|
+
attribute :vchip_rating
|
32
|
+
end
|
33
|
+
|
34
|
+
class Episode < Series
|
35
|
+
attribute :runtime
|
36
|
+
end
|
37
|
+
|
38
|
+
class TestModelRailsIntegration < MiniTest::Unit::TestCase
|
39
|
+
|
40
|
+
def test_class_attributes_are_inheritable
|
41
|
+
program_attributes = [:title, :genres]
|
42
|
+
movie_attributes = [:mpaa_rating, :runtime]
|
43
|
+
series_attributes = [:vchip_rating]
|
44
|
+
episode_attributes = [:runtime]
|
45
|
+
|
46
|
+
assert_equal program_attributes, Program.attributes.keys
|
47
|
+
assert_equal program_attributes + movie_attributes, Movie.attributes.keys
|
48
|
+
assert_equal program_attributes + series_attributes, Series.attributes.keys
|
49
|
+
assert_equal program_attributes + series_attributes + episode_attributes, Episode.attributes.keys
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_default_attributes_are_inheritable
|
53
|
+
assert_equal nil, Movie.attributes[:title]
|
54
|
+
assert_equal [], Movie.attributes[:genres]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_instance_attributes_are_inheritable
|
58
|
+
episode = Episode.new(:title => 'Family Guy', :genres => ['Comedy'], :vchip_rating => 'TVPG', :runtime => 30)
|
59
|
+
|
60
|
+
assert_equal [:title, :genres, :vchip_rating, :runtime], episode.attributes.keys
|
61
|
+
assert_equal 'Family Guy', episode.title
|
62
|
+
assert_equal ['Comedy'], episode.genres
|
63
|
+
assert_equal 30, episode.runtime
|
64
|
+
assert_equal 'TVPG', episode.vchip_rating
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_class_attributes_from_subclasses_do_not_propogate_up_ancestor_chain
|
68
|
+
assert_equal [:title, :genres, :vchip_rating], Series.attributes.keys
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_instance_attributes_from_subclasses_do_not_propogate_up_ancestor_chain
|
72
|
+
series = Series.new(:title => 'Family Guy', :genres => ['Comedy'], :vchip_rating => 'TVPG')
|
73
|
+
assert_equal [:title, :genres, :vchip_rating], series.attributes.keys
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|