samflores-couchrest 0.2.1 → 0.12.3

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 (66) hide show
  1. data/README.md +10 -34
  2. data/Rakefile +5 -2
  3. data/bin/couchdir +20 -0
  4. data/examples/model/example.rb +13 -19
  5. data/examples/word_count/word_count.rb +24 -3
  6. data/examples/word_count/word_count_query.rb +6 -7
  7. data/lib/couchrest/core/database.rb +49 -126
  8. data/lib/couchrest/core/document.rb +25 -58
  9. data/lib/couchrest/core/model.rb +612 -0
  10. data/lib/couchrest/core/server.rb +10 -47
  11. data/lib/couchrest/core/validations.rb +328 -0
  12. data/lib/couchrest/monkeypatches.rb +0 -95
  13. data/lib/couchrest.rb +10 -57
  14. data/spec/couchrest/core/database_spec.rb +68 -183
  15. data/spec/couchrest/core/design_spec.rb +1 -1
  16. data/spec/couchrest/core/document_spec.rb +104 -285
  17. data/spec/couchrest/core/model_spec.rb +855 -0
  18. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  19. data/spec/spec_helper.rb +7 -13
  20. metadata +17 -83
  21. data/examples/word_count/word_count_views.rb +0 -26
  22. data/lib/couchrest/core/response.rb +0 -16
  23. data/lib/couchrest/mixins/attachments.rb +0 -31
  24. data/lib/couchrest/mixins/callbacks.rb +0 -483
  25. data/lib/couchrest/mixins/design_doc.rb +0 -64
  26. data/lib/couchrest/mixins/document_queries.rb +0 -48
  27. data/lib/couchrest/mixins/extended_attachments.rb +0 -68
  28. data/lib/couchrest/mixins/extended_document_mixins.rb +0 -6
  29. data/lib/couchrest/mixins/properties.rb +0 -125
  30. data/lib/couchrest/mixins/validation.rb +0 -234
  31. data/lib/couchrest/mixins/views.rb +0 -168
  32. data/lib/couchrest/mixins.rb +0 -4
  33. data/lib/couchrest/more/casted_model.rb +0 -28
  34. data/lib/couchrest/more/extended_document.rb +0 -217
  35. data/lib/couchrest/more/property.rb +0 -40
  36. data/lib/couchrest/support/blank.rb +0 -42
  37. data/lib/couchrest/support/class.rb +0 -191
  38. data/lib/couchrest/validation/auto_validate.rb +0 -163
  39. data/lib/couchrest/validation/contextual_validators.rb +0 -78
  40. data/lib/couchrest/validation/validation_errors.rb +0 -118
  41. data/lib/couchrest/validation/validators/absent_field_validator.rb +0 -74
  42. data/lib/couchrest/validation/validators/confirmation_validator.rb +0 -99
  43. data/lib/couchrest/validation/validators/format_validator.rb +0 -117
  44. data/lib/couchrest/validation/validators/formats/email.rb +0 -66
  45. data/lib/couchrest/validation/validators/formats/url.rb +0 -43
  46. data/lib/couchrest/validation/validators/generic_validator.rb +0 -120
  47. data/lib/couchrest/validation/validators/length_validator.rb +0 -134
  48. data/lib/couchrest/validation/validators/method_validator.rb +0 -89
  49. data/lib/couchrest/validation/validators/numeric_validator.rb +0 -104
  50. data/lib/couchrest/validation/validators/required_field_validator.rb +0 -109
  51. data/spec/couchrest/core/server_spec.rb +0 -35
  52. data/spec/couchrest/more/casted_extended_doc_spec.rb +0 -40
  53. data/spec/couchrest/more/casted_model_spec.rb +0 -98
  54. data/spec/couchrest/more/extended_doc_attachment_spec.rb +0 -130
  55. data/spec/couchrest/more/extended_doc_spec.rb +0 -509
  56. data/spec/couchrest/more/extended_doc_view_spec.rb +0 -207
  57. data/spec/couchrest/more/property_spec.rb +0 -130
  58. data/spec/couchrest/support/class_spec.rb +0 -59
  59. data/spec/fixtures/more/article.rb +0 -34
  60. data/spec/fixtures/more/card.rb +0 -20
  61. data/spec/fixtures/more/course.rb +0 -14
  62. data/spec/fixtures/more/event.rb +0 -6
  63. data/spec/fixtures/more/invoice.rb +0 -17
  64. data/spec/fixtures/more/person.rb +0 -8
  65. data/spec/fixtures/more/question.rb +0 -6
  66. data/spec/fixtures/more/service.rb +0 -12
@@ -1,207 +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
- reset_test_db!
194
- Article.by_date
195
- Article.view_by :field
196
- Article.by_field
197
- end
198
- it "should clean them up" do
199
- ddocs = Article.all_design_doc_versions
200
- Article.view_by :stream
201
- Article.by_stream
202
- Article.cleanup_design_docs!
203
- ddocs = Article.all_design_doc_versions
204
- ddocs["rows"].length.should == 1
205
- end
206
- end
207
- end
@@ -1,130 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
- require File.join(FIXTURE_PATH, 'more', 'card')
3
- require File.join(FIXTURE_PATH, 'more', 'invoice')
4
- require File.join(FIXTURE_PATH, 'more', 'service')
5
- require File.join(FIXTURE_PATH, 'more', 'event')
6
-
7
-
8
- describe "ExtendedDocument properties" do
9
-
10
- before(:each) do
11
- reset_test_db!
12
- @card = Card.new(:first_name => "matt")
13
- end
14
-
15
- it "should be accessible from the object" do
16
- @card.properties.should be_an_instance_of(Array)
17
- @card.properties.map{|p| p.name}.should include("first_name")
18
- end
19
-
20
- it "should let you access a property value (getter)" do
21
- @card.first_name.should == "matt"
22
- end
23
-
24
- it "should let you set a property value (setter)" do
25
- @card.last_name = "Aimonetti"
26
- @card.last_name.should == "Aimonetti"
27
- end
28
-
29
- it "should not let you set a property value if it's read only" do
30
- lambda{@card.read_only_value = "test"}.should raise_error
31
- end
32
-
33
- it "should let you use an alias for an attribute" do
34
- @card.last_name = "Aimonetti"
35
- @card.family_name.should == "Aimonetti"
36
- @card.family_name.should == @card.last_name
37
- end
38
-
39
- it "should be auto timestamped" do
40
- @card.created_at.should be_nil
41
- @card.updated_at.should be_nil
42
- @card.save.should be_true
43
- @card.created_at.should_not be_nil
44
- @card.updated_at.should_not be_nil
45
- end
46
-
47
- describe "validation" do
48
- before(:each) do
49
- @invoice = Invoice.new(:client_name => "matt", :employee_name => "Chris", :location => "San Diego, CA")
50
- end
51
-
52
- it "should be able to be validated" do
53
- @card.valid?.should == true
54
- end
55
-
56
- it "should let you validate the presence of an attribute" do
57
- @card.first_name = nil
58
- @card.should_not be_valid
59
- @card.errors.should_not be_empty
60
- @card.errors.on(:first_name).should == ["First name must not be blank"]
61
- end
62
-
63
- it "should validate the presence of 2 attributes" do
64
- @invoice.clear
65
- @invoice.should_not be_valid
66
- @invoice.errors.should_not be_empty
67
- @invoice.errors.on(:client_name).first.should == "Client name must not be blank"
68
- @invoice.errors.on(:employee_name).should_not be_empty
69
- end
70
-
71
- it "should let you set an error message" do
72
- @invoice.location = nil
73
- @invoice.valid?
74
- @invoice.errors.on(:location).should == ["Hey stupid!, you forgot the location"]
75
- end
76
-
77
- it "should validate before saving" do
78
- @invoice.location = nil
79
- @invoice.should_not be_valid
80
- @invoice.save.should be_false
81
- @invoice.should be_new_document
82
- end
83
- end
84
-
85
- describe "autovalidation" do
86
- before(:each) do
87
- @service = Service.new(:name => "Coumpound analysis", :price => 3_000)
88
- end
89
-
90
- it "should be valid" do
91
- @service.should be_valid
92
- end
93
-
94
- it "should not respond to properties not setup" do
95
- @service.respond_to?(:client_name).should be_false
96
- end
97
-
98
- describe "property :name, :length => 4...20" do
99
-
100
- it "should autovalidate the presence when length is set" do
101
- @service.name = nil
102
- @service.should_not be_valid
103
- @service.errors.should_not be_nil
104
- @service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
105
- end
106
-
107
- it "should autovalidate the correct length" do
108
- @service.name = "a"
109
- @service.should_not be_valid
110
- @service.errors.should_not be_nil
111
- @service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
112
- end
113
- end
114
- end
115
-
116
- describe "casting" do
117
- describe "cast keys to any type" do
118
- before(:all) do
119
- event_doc = { :subject => "Some event", :occurs_at => Time.now }
120
- e = Event.database.save_doc event_doc
121
-
122
- @event = Event.get e['id']
123
- end
124
- it "should cast created_at to Time" do
125
- @event['occurs_at'].should be_an_instance_of(Time)
126
- end
127
- end
128
- end
129
-
130
- 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,20 +0,0 @@
1
- class Card < CouchRest::ExtendedDocument
2
- # Include the validation module to get access to the validation methods
3
- include CouchRest::Validation
4
- # set the auto_validation before defining the properties
5
- auto_validate!
6
-
7
- # Set the default database to use
8
- use_database TEST_SERVER.default_database
9
-
10
- # Official Schema
11
- property :first_name
12
- property :last_name, :alias => :family_name
13
- property :read_only_value, :read_only => true
14
-
15
- timestamps!
16
-
17
- # Validation
18
- validates_present :first_name
19
-
20
- 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,17 +0,0 @@
1
- class Invoice < CouchRest::ExtendedDocument
2
- # Include the validation module to get access to the validation methods
3
- include CouchRest::Validation
4
-
5
- # Set the default database to use
6
- use_database TEST_SERVER.default_database
7
-
8
- # Official Schema
9
- property :client_name
10
- property :employee_name
11
- property :location
12
-
13
- # Validation
14
- validates_present :client_name, :employee_name
15
- validates_present :location, :message => "Hey stupid!, you forgot the location"
16
-
17
- 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
@@ -1,12 +0,0 @@
1
- class Service < CouchRest::ExtendedDocument
2
- # Include the validation module to get access to the validation methods
3
- include CouchRest::Validation
4
- auto_validate!
5
- # Set the default database to use
6
- use_database TEST_SERVER.default_database
7
-
8
- # Official Schema
9
- property :name, :length => 4...20
10
- property :price, :type => Integer
11
-
12
- end