mattetti-couchrest 0.2.1.0 → 0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/README.md +6 -31
  2. data/Rakefile +1 -1
  3. data/examples/model/example.rb +13 -19
  4. data/lib/couchrest/core/database.rb +4 -3
  5. data/lib/couchrest/core/model.rb +615 -0
  6. data/lib/couchrest/core/response.rb +4 -5
  7. data/lib/couchrest/core/server.rb +1 -1
  8. data/lib/couchrest/mixins/callbacks.rb +33 -74
  9. data/lib/couchrest/mixins/design_doc.rb +1 -2
  10. data/lib/couchrest/mixins/document_queries.rb +1 -1
  11. data/lib/couchrest/mixins/extended_document_mixins.rb +1 -2
  12. data/lib/couchrest/mixins/properties.rb +3 -8
  13. data/lib/couchrest/mixins/validation.rb +1 -2
  14. data/lib/couchrest/mixins/views.rb +5 -5
  15. data/lib/couchrest/monkeypatches.rb +48 -65
  16. data/lib/couchrest/more/extended_document.rb +8 -75
  17. data/lib/couchrest/more/property.rb +1 -12
  18. data/lib/couchrest/support/class.rb +132 -148
  19. data/lib/couchrest.rb +8 -33
  20. data/spec/couchrest/core/database_spec.rb +23 -28
  21. data/spec/couchrest/core/model_spec.rb +856 -0
  22. data/spec/couchrest/more/casted_model_spec.rb +0 -14
  23. data/spec/couchrest/more/extended_doc_spec.rb +4 -450
  24. data/spec/couchrest/more/property_spec.rb +5 -16
  25. data/spec/spec_helper.rb +0 -4
  26. metadata +3 -16
  27. data/lib/couchrest/mixins/extended_attachments.rb +0 -68
  28. data/lib/couchrest/validation/validators/confirmation_validator.rb +0 -99
  29. data/spec/couchrest/more/casted_extended_doc_spec.rb +0 -40
  30. data/spec/couchrest/more/extended_doc_attachment_spec.rb +0 -129
  31. data/spec/couchrest/more/extended_doc_view_spec.rb +0 -206
  32. data/spec/couchrest/support/class_spec.rb +0 -59
  33. data/spec/fixtures/more/article.rb +0 -34
  34. data/spec/fixtures/more/course.rb +0 -14
  35. data/spec/fixtures/more/event.rb +0 -6
  36. data/spec/fixtures/more/person.rb +0 -8
  37. data/spec/fixtures/more/question.rb +0 -6
@@ -1,68 +0,0 @@
1
- module CouchRest
2
- module Mixins
3
- module ExtendedAttachments
4
-
5
- # creates a file attachment to the current doc
6
- def create_attachment(args={})
7
- raise ArgumentError unless args[:file] && args[:name]
8
- return if has_attachment?(args[:name])
9
- self['_attachments'] ||= {}
10
- set_attachment_attr(args)
11
- rescue ArgumentError => e
12
- raise ArgumentError, 'You must specify :file and :name'
13
- end
14
-
15
- # reads the data from an attachment
16
- def read_attachment(attachment_name)
17
- Base64.decode64(database.fetch_attachment(self, attachment_name))
18
- end
19
-
20
- # modifies a file attachment on the current doc
21
- def update_attachment(args={})
22
- raise ArgumentError unless args[:file] && args[:name]
23
- return unless has_attachment?(args[:name])
24
- delete_attachment(args[:name])
25
- set_attachment_attr(args)
26
- rescue ArgumentError => e
27
- raise ArgumentError, 'You must specify :file and :name'
28
- end
29
-
30
- # deletes a file attachment from the current doc
31
- def delete_attachment(attachment_name)
32
- return unless self['_attachments']
33
- self['_attachments'].delete attachment_name
34
- end
35
-
36
- # returns true if attachment_name exists
37
- def has_attachment?(attachment_name)
38
- !!(self['_attachments'] && self['_attachments'][attachment_name] && !self['_attachments'][attachment_name].empty?)
39
- end
40
-
41
- # returns URL to fetch the attachment from
42
- def attachment_url(attachment_name)
43
- return unless has_attachment?(attachment_name)
44
- "#{database.root}/#{self.id}/#{attachment_name}"
45
- end
46
-
47
- private
48
-
49
- def encode_attachment(data)
50
- ::Base64.encode64(data).gsub(/\r|\n/,'')
51
- end
52
-
53
- def get_mime_type(file)
54
- ::MIME::Types.type_for(file.path).empty? ?
55
- 'text\/plain' : MIME::Types.type_for(file.path).first.content_type.gsub(/\//,'\/')
56
- end
57
-
58
- def set_attachment_attr(args)
59
- content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file])
60
- self['_attachments'][args[:name]] = {
61
- 'content-type' => content_type,
62
- 'data' => encode_attachment(args[:file].read)
63
- }
64
- end
65
-
66
- end # module ExtendedAttachments
67
- end
68
- end
@@ -1,99 +0,0 @@
1
- # Extracted from dm-validations 0.9.10
2
- #
3
- # Copyright (c) 2007 Guy van den Berg
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining
6
- # a copy of this software and associated documentation files (the
7
- # "Software"), to deal in the Software without restriction, including
8
- # without limitation the rights to use, copy, modify, merge, publish,
9
- # distribute, sublicense, and/or sell copies of the Software, and to
10
- # permit persons to whom the Software is furnished to do so, subject to
11
- # the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be
14
- # included in all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- module CouchRest
25
- module Validation
26
-
27
- ##
28
- #
29
- # @author Guy van den Berg
30
- # @since 0.9
31
- class ConfirmationValidator < GenericValidator
32
-
33
- def initialize(field_name, options = {})
34
- super
35
- @options = options
36
- @field_name, @confirm_field_name = field_name, (options[:confirm] || "#{field_name}_confirmation").to_sym
37
- @options[:allow_nil] = true unless @options.has_key?(:allow_nil)
38
- end
39
-
40
- def call(target)
41
- unless valid?(target)
42
- error_message = @options[:message] || ValidationErrors.default_error_message(:confirmation, field_name)
43
- add_error(target, error_message, field_name)
44
- return false
45
- end
46
-
47
- return true
48
- end
49
-
50
- def valid?(target)
51
- field_value = target.send(field_name)
52
- return true if @options[:allow_nil] && field_value.nil?
53
- return false if !@options[:allow_nil] && field_value.nil?
54
-
55
- confirm_value = target.instance_variable_get("@#{@confirm_field_name}")
56
- field_value == confirm_value
57
- end
58
-
59
- end # class ConfirmationValidator
60
-
61
- module ValidatesIsConfirmed
62
-
63
- ##
64
- # Validates that the given attribute is confirmed by another attribute.
65
- # A common use case scenario is when you require a user to confirm their
66
- # password, for which you use both password and password_confirmation
67
- # attributes.
68
- #
69
- # @option :allow_nil<Boolean> true/false (default is true)
70
- # @option :confirm<Symbol> the attribute that you want to validate
71
- # against (default is firstattr_confirmation)
72
- #
73
- # @example [Usage]
74
- #
75
- # class Page < Hash
76
- # include CouchRest::ExtendedModel
77
- # include CouchRest::Validations
78
- #
79
- # property :password, String
80
- # property :email, String
81
- # attr_accessor :password_confirmation
82
- # attr_accessor :email_repeated
83
- #
84
- # validates_is_confirmed :password
85
- # validates_is_confirmed :email, :confirm => :email_repeated
86
- #
87
- # # a call to valid? will return false unless:
88
- # # password == password_confirmation
89
- # # and
90
- # # email == email_repeated
91
- #
92
- def validates_is_confirmed(*fields)
93
- opts = opts_from_validator_args(fields)
94
- add_validator_to_context(opts, fields, CouchRest::Validation::ConfirmationValidator)
95
- end
96
-
97
- end # module ValidatesIsConfirmed
98
- end # module Validation
99
- end # module CouchRest
@@ -1,40 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
- require File.join(FIXTURE_PATH, 'more', 'card')
3
-
4
- class Car < CouchRest::ExtendedDocument
5
- use_database TEST_SERVER.default_database
6
-
7
- property :name
8
- property :driver, :cast_as => 'Driver'
9
- end
10
-
11
- class Driver < CouchRest::ExtendedDocument
12
- use_database TEST_SERVER.default_database
13
- # You have to add a casted_by accessor if you want to reach a casted extended doc parent
14
- attr_accessor :casted_by
15
-
16
- property :name
17
- end
18
-
19
- describe "casting an extended document" do
20
-
21
- before(:each) do
22
- @car = Car.new(:name => 'Renault 306')
23
- @driver = Driver.new(:name => 'Matt')
24
- end
25
-
26
- # it "should not create an empty casted object" do
27
- # @car.driver.should be_nil
28
- # end
29
-
30
- it "should let you assign the casted attribute after instantializing an object" do
31
- @car.driver = @driver
32
- @car.driver.name.should == 'Matt'
33
- end
34
-
35
- it "should let the casted document who casted it" do
36
- Car.new(:name => 'Renault 306', :driver => @driver)
37
- @car.driver.casted_by.should == @car
38
- end
39
-
40
- end
@@ -1,129 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
2
-
3
- describe "ExtendedDocument attachments" do
4
-
5
- describe "#has_attachment?" do
6
- before(:each) do
7
- @obj = Basic.new
8
- @obj.save.should == true
9
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
10
- @attachment_name = 'my_attachment'
11
- @obj.create_attachment(:file => @file, :name => @attachment_name)
12
- end
13
-
14
- it 'should return false if there is no attachment' do
15
- @obj.has_attachment?('bogus').should be_false
16
- end
17
-
18
- it 'should return true if there is an attachment' do
19
- @obj.has_attachment?(@attachment_name).should be_true
20
- end
21
-
22
- it 'should return true if an object with an attachment is reloaded' do
23
- @obj.save.should be_true
24
- reloaded_obj = Basic.get(@obj.id)
25
- reloaded_obj.has_attachment?(@attachment_name).should be_true
26
- end
27
-
28
- it 'should return false if an attachment has been removed' do
29
- @obj.delete_attachment(@attachment_name)
30
- @obj.has_attachment?(@attachment_name).should be_false
31
- end
32
- end
33
-
34
- describe "creating an attachment" do
35
- before(:each) do
36
- @obj = Basic.new
37
- @obj.save.should == true
38
- @file_ext = File.open(FIXTURE_PATH + '/attachments/test.html')
39
- @file_no_ext = File.open(FIXTURE_PATH + '/attachments/README')
40
- @attachment_name = 'my_attachment'
41
- @content_type = 'media/mp3'
42
- end
43
-
44
- it "should create an attachment from file with an extension" do
45
- @obj.create_attachment(:file => @file_ext, :name => @attachment_name)
46
- @obj.save.should == true
47
- reloaded_obj = Basic.get(@obj.id)
48
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
49
- end
50
-
51
- it "should create an attachment from file without an extension" do
52
- @obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
53
- @obj.save.should == true
54
- reloaded_obj = Basic.get(@obj.id)
55
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
56
- end
57
-
58
- it 'should raise ArgumentError if :file is missing' do
59
- lambda{ @obj.create_attachment(:name => @attachment_name) }.should raise_error
60
- end
61
-
62
- it 'should raise ArgumentError if :name is missing' do
63
- lambda{ @obj.create_attachment(:file => @file_ext) }.should raise_error
64
- end
65
-
66
- it 'should set the content-type if passed' do
67
- @obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
68
- @obj['_attachments'][@attachment_name]['content-type'].should == @content_type
69
- end
70
- end
71
-
72
- describe 'reading, updating, and deleting an attachment' do
73
- before(:each) do
74
- @obj = Basic.new
75
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
76
- @attachment_name = 'my_attachment'
77
- @obj.create_attachment(:file => @file, :name => @attachment_name)
78
- @obj.save.should == true
79
- @file.rewind
80
- @content_type = 'media/mp3'
81
- end
82
-
83
- it 'should read an attachment that exists' do
84
- @obj.read_attachment(@attachment_name).should == @file.read
85
- end
86
-
87
- it 'should update an attachment that exists' do
88
- file = File.open(FIXTURE_PATH + '/attachments/README')
89
- @file.should_not == file
90
- @obj.update_attachment(:file => file, :name => @attachment_name)
91
- @obj.save
92
- reloaded_obj = Basic.get(@obj.id)
93
- file.rewind
94
- reloaded_obj.read_attachment(@attachment_name).should_not == @file.read
95
- reloaded_obj.read_attachment(@attachment_name).should == file.read
96
- end
97
-
98
- it 'should se the content-type if passed' do
99
- file = File.open(FIXTURE_PATH + '/attachments/README')
100
- @file.should_not == file
101
- @obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
102
- @obj['_attachments'][@attachment_name]['content-type'].should == @content_type
103
- end
104
-
105
- it 'should delete an attachment that exists' do
106
- @obj.delete_attachment(@attachment_name)
107
- @obj.save
108
- lambda{Basic.get(@obj.id).read_attachment(@attachment_name)}.should raise_error
109
- end
110
- end
111
-
112
- describe "#attachment_url" do
113
- before(:each) do
114
- @obj = Basic.new
115
- @file = File.open(FIXTURE_PATH + '/attachments/test.html')
116
- @attachment_name = 'my_attachment'
117
- @obj.create_attachment(:file => @file, :name => @attachment_name)
118
- @obj.save.should == true
119
- end
120
-
121
- it 'should return nil if attachment does not exist' do
122
- @obj.attachment_url('bogus').should be_nil
123
- end
124
-
125
- it 'should return the attachment URL as specified by CouchDB HttpDocumentApi' do
126
- @obj.attachment_url(@attachment_name).should == "#{Basic.database}/#{@obj.id}/#{@attachment_name}"
127
- end
128
- end
129
- end
@@ -1,206 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
2
- require File.join(FIXTURE_PATH, 'more', 'article')
3
- require File.join(FIXTURE_PATH, 'more', 'course')
4
-
5
- describe "ExtendedDocument views" do
6
-
7
- describe "a model with simple views and a default param" do
8
- before(:all) do
9
- Article.all.map{|a| a.destroy(true)}
10
- Article.database.bulk_delete
11
- written_at = Time.now - 24 * 3600 * 7
12
- @titles = ["this and that", "also interesting", "more fun", "some junk"]
13
- @titles.each do |title|
14
- a = Article.new(:title => title)
15
- a.date = written_at
16
- a.save
17
- written_at += 24 * 3600
18
- end
19
- end
20
-
21
- it "should have a design doc" do
22
- Article.design_doc["views"]["by_date"].should_not be_nil
23
- end
24
-
25
- it "should save the design doc" do
26
- Article.by_date #rescue nil
27
- doc = Article.database.get Article.design_doc.id
28
- doc['views']['by_date'].should_not be_nil
29
- end
30
-
31
- it "should return the matching raw view result" do
32
- view = Article.by_date :raw => true
33
- view['rows'].length.should == 4
34
- end
35
-
36
- it "should not include non-Articles" do
37
- Article.database.save_doc({"date" => 1})
38
- view = Article.by_date :raw => true
39
- view['rows'].length.should == 4
40
- end
41
-
42
- it "should return the matching objects (with default argument :descending => true)" do
43
- articles = Article.by_date
44
- articles.collect{|a|a.title}.should == @titles.reverse
45
- end
46
-
47
- it "should allow you to override default args" do
48
- articles = Article.by_date :descending => false
49
- articles.collect{|a|a.title}.should == @titles
50
- end
51
- end
52
-
53
- describe "another model with a simple view" do
54
- before(:all) do
55
- reset_test_db!
56
- %w{aaa bbb ddd eee}.each do |title|
57
- Course.new(:title => title).save
58
- end
59
- end
60
- it "should make the design doc upon first query" do
61
- Course.by_title
62
- doc = Course.design_doc
63
- doc['views']['all']['map'].should include('Course')
64
- end
65
- it "should can query via view" do
66
- # register methods with method-missing, for local dispatch. method
67
- # missing lookup table, no heuristics.
68
- view = Course.view :by_title
69
- designed = Course.by_title
70
- view.should == designed
71
- end
72
- it "should get them" do
73
- rs = Course.by_title
74
- rs.length.should == 4
75
- end
76
- it "should yield" do
77
- courses = []
78
- rs = Course.by_title # remove me
79
- Course.view(:by_title) do |course|
80
- courses << course
81
- end
82
- courses[0]["doc"]["title"].should =='aaa'
83
- end
84
- end
85
-
86
-
87
- describe "a ducktype view" do
88
- before(:all) do
89
- @id = TEST_SERVER.default_database.save_doc({:dept => true})['id']
90
- end
91
- it "should setup" do
92
- duck = Course.get(@id) # from a different db
93
- duck["dept"].should == true
94
- end
95
- it "should make the design doc" do
96
- @as = Course.by_dept
97
- @doc = Course.design_doc
98
- @doc["views"]["by_dept"]["map"].should_not include("couchrest")
99
- end
100
- it "should not look for class" do |variable|
101
- @as = Course.by_dept
102
- @as[0]['_id'].should == @id
103
- end
104
- end
105
-
106
- describe "a model with a compound key view" do
107
- before(:all) do
108
- Article.design_doc_fresh = false
109
- Article.by_user_id_and_date.each{|a| a.destroy(true)}
110
- Article.database.bulk_delete
111
- written_at = Time.now - 24 * 3600 * 7
112
- @titles = ["uniq one", "even more interesting", "less fun", "not junk"]
113
- @user_ids = ["quentin", "aaron"]
114
- @titles.each_with_index do |title,i|
115
- u = i % 2
116
- a = Article.new(:title => title, :user_id => @user_ids[u])
117
- a.date = written_at
118
- a.save
119
- written_at += 24 * 3600
120
- end
121
- end
122
- it "should create the design doc" do
123
- Article.by_user_id_and_date rescue nil
124
- doc = Article.design_doc
125
- doc['views']['by_date'].should_not be_nil
126
- end
127
- it "should sort correctly" do
128
- articles = Article.by_user_id_and_date
129
- articles.collect{|a|a['user_id']}.should == ['aaron', 'aaron', 'quentin',
130
- 'quentin']
131
- articles[1].title.should == 'not junk'
132
- end
133
- it "should be queryable with couchrest options" do
134
- articles = Article.by_user_id_and_date :limit => 1, :startkey => 'quentin'
135
- articles.length.should == 1
136
- articles[0].title.should == "even more interesting"
137
- end
138
- end
139
-
140
- describe "with a custom view" do
141
- before(:all) do
142
- @titles = ["very uniq one", "even less interesting", "some fun",
143
- "really junk", "crazy bob"]
144
- @tags = ["cool", "lame"]
145
- @titles.each_with_index do |title,i|
146
- u = i % 2
147
- a = Article.new(:title => title, :tags => [@tags[u]])
148
- a.save
149
- end
150
- end
151
- it "should be available raw" do
152
- view = Article.by_tags :raw => true
153
- view['rows'].length.should == 5
154
- end
155
-
156
- it "should be default to :reduce => false" do
157
- ars = Article.by_tags
158
- ars.first.tags.first.should == 'cool'
159
- end
160
-
161
- it "should be raw when reduce is true" do
162
- view = Article.by_tags :reduce => true, :group => true
163
- view['rows'].find{|r|r['key'] == 'cool'}['value'].should == 3
164
- end
165
- end
166
-
167
- # TODO: moved to Design, delete
168
- describe "adding a view" do
169
- before(:each) do
170
- reset_test_db!
171
- Article.by_date
172
- @design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
173
- end
174
- it "should not create a design doc on view definition" do
175
- Article.view_by :created_at
176
- newdocs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
177
- newdocs["rows"].length.should == @design_docs["rows"].length
178
- end
179
- it "should create a new version of the design document on view access" do
180
- old_design_doc = Article.database.documents(:key => @design_docs["rows"].first["key"], :include_docs => true)["rows"][0]["doc"]
181
- Article.view_by :updated_at
182
- Article.by_updated_at
183
- newdocs = Article.database.documents({:startkey => "_design/", :endkey => "_design/\u9999"})
184
-
185
- doc = Article.database.documents(:key => @design_docs["rows"].first["key"], :include_docs => true)["rows"][0]["doc"]
186
- doc["_rev"].should_not == old_design_doc["_rev"]
187
- doc["views"].keys.should include("by_updated_at")
188
- end
189
- end
190
-
191
- describe "with a lot of designs left around" do
192
- before(:each) do
193
- Article.by_date
194
- Article.view_by :field
195
- Article.by_field
196
- end
197
- it "should clean them up" do
198
- ddocs = Article.all_design_doc_versions
199
- Article.view_by :stream
200
- Article.by_stream
201
- Article.cleanup_design_docs!
202
- ddocs = Article.all_design_doc_versions
203
- ddocs["rows"].length.should == 1
204
- end
205
- end
206
- end
@@ -1,59 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
- require File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'couchrest', 'support', 'class')
3
-
4
- describe CouchRest::ClassExtension do
5
-
6
- before :all do
7
- class FullyDefinedClassExtensions
8
- def self.respond_to?(method)
9
- if CouchRest::ClassExtension::InstanceMethods.instance_methods.include?(method)
10
- true
11
- else
12
- super
13
- end
14
- end
15
- end
16
-
17
- class PartDefinedClassExtensions
18
- def self.respond_to?(method)
19
- methods = CouchRest::ClassExtension::InstanceMethods.instance_methods
20
- methods.delete('cattr_reader')
21
-
22
- if methods.include?(method)
23
- false
24
- else
25
- super
26
- end
27
- end
28
- end
29
-
30
- class NoClassExtensions
31
- def self.respond_to?(method)
32
- if CouchRest::ClassExtension::InstanceMethods.instance_methods.include?(method)
33
- false
34
- else
35
- super
36
- end
37
- end
38
- end
39
-
40
-
41
- end
42
-
43
- it "should not include InstanceMethods if the class extensions are already defined" do
44
- FullyDefinedClassExtensions.send(:include, CouchRest::ClassExtension)
45
- FullyDefinedClassExtensions.ancestors.should_not include(CouchRest::ClassExtension::InstanceMethods)
46
- end
47
-
48
- it "should raise RuntimeError if the class extensions are only partially defined" do
49
- lambda {
50
- PartDefinedClassExtensions.send(:include, CouchRest::ClassExtension)
51
- }.should raise_error(RuntimeError)
52
- end
53
-
54
- it "should include class extensions if they are not already defined" do
55
- NoClassExtensions.send(:include, CouchRest::ClassExtension)
56
- NoClassExtensions.ancestors.should include(CouchRest::ClassExtension::InstanceMethods)
57
- end
58
-
59
- end
@@ -1,34 +0,0 @@
1
- class Article < CouchRest::ExtendedDocument
2
- use_database TEST_SERVER.default_database
3
- unique_id :slug
4
-
5
- view_by :date, :descending => true
6
- view_by :user_id, :date
7
-
8
- view_by :tags,
9
- :map =>
10
- "function(doc) {
11
- if (doc['couchrest-type'] == 'Article' && doc.tags) {
12
- doc.tags.forEach(function(tag){
13
- emit(tag, 1);
14
- });
15
- }
16
- }",
17
- :reduce =>
18
- "function(keys, values, rereduce) {
19
- return sum(values);
20
- }"
21
-
22
- property :date
23
- property :slug, :read_only => true
24
- property :title
25
- property :tags
26
-
27
- timestamps!
28
-
29
- save_callback :before, :generate_slug_from_title
30
-
31
- def generate_slug_from_title
32
- self['slug'] = title.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new_document?
33
- end
34
- end
@@ -1,14 +0,0 @@
1
- require File.join(FIXTURE_PATH, 'more', 'question')
2
- require File.join(FIXTURE_PATH, 'more', 'person')
3
-
4
- class Course < CouchRest::ExtendedDocument
5
- use_database TEST_SERVER.default_database
6
-
7
- property :title
8
- property :questions, :cast_as => ['Question']
9
- property :professor, :cast_as => 'Person'
10
- property :final_test_at, :cast_as => 'Time'
11
-
12
- view_by :title
13
- view_by :dept, :ducktype => true
14
- end
@@ -1,6 +0,0 @@
1
- class Event < CouchRest::ExtendedDocument
2
- use_database TEST_SERVER.default_database
3
-
4
- property :subject
5
- property :occurs_at, :cast_as => 'Time', :send => 'parse'
6
- end
@@ -1,8 +0,0 @@
1
- class Person < Hash
2
- include ::CouchRest::CastedModel
3
- property :name
4
-
5
- def last_name
6
- name.last
7
- end
8
- end
@@ -1,6 +0,0 @@
1
- class Question < Hash
2
- include ::CouchRest::CastedModel
3
-
4
- property :q
5
- property :a
6
- end