samflores-couchrest 0.2.1 → 0.12.3

Sign up to get free protection for your applications and to get access to all the features.
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