oz-couchrest 0.29

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 (95) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +95 -0
  3. data/Rakefile +74 -0
  4. data/THANKS.md +18 -0
  5. data/examples/model/example.rb +144 -0
  6. data/examples/word_count/markov +38 -0
  7. data/examples/word_count/views/books/chunked-map.js +3 -0
  8. data/examples/word_count/views/books/united-map.js +1 -0
  9. data/examples/word_count/views/markov/chain-map.js +6 -0
  10. data/examples/word_count/views/markov/chain-reduce.js +7 -0
  11. data/examples/word_count/views/word_count/count-map.js +6 -0
  12. data/examples/word_count/views/word_count/count-reduce.js +3 -0
  13. data/examples/word_count/word_count.rb +46 -0
  14. data/examples/word_count/word_count_query.rb +40 -0
  15. data/examples/word_count/word_count_views.rb +26 -0
  16. data/lib/couchrest.rb +198 -0
  17. data/lib/couchrest/commands/generate.rb +71 -0
  18. data/lib/couchrest/commands/push.rb +103 -0
  19. data/lib/couchrest/core/database.rb +326 -0
  20. data/lib/couchrest/core/design.rb +91 -0
  21. data/lib/couchrest/core/document.rb +87 -0
  22. data/lib/couchrest/core/response.rb +16 -0
  23. data/lib/couchrest/core/server.rb +88 -0
  24. data/lib/couchrest/core/view.rb +4 -0
  25. data/lib/couchrest/helper/pager.rb +103 -0
  26. data/lib/couchrest/helper/streamer.rb +44 -0
  27. data/lib/couchrest/helper/upgrade.rb +51 -0
  28. data/lib/couchrest/mixins.rb +4 -0
  29. data/lib/couchrest/mixins/attachments.rb +31 -0
  30. data/lib/couchrest/mixins/callbacks.rb +483 -0
  31. data/lib/couchrest/mixins/class_proxy.rb +112 -0
  32. data/lib/couchrest/mixins/collection.rb +222 -0
  33. data/lib/couchrest/mixins/design_doc.rb +114 -0
  34. data/lib/couchrest/mixins/document_queries.rb +53 -0
  35. data/lib/couchrest/mixins/extended_attachments.rb +74 -0
  36. data/lib/couchrest/mixins/extended_document_mixins.rb +8 -0
  37. data/lib/couchrest/mixins/properties.rb +125 -0
  38. data/lib/couchrest/mixins/validation.rb +257 -0
  39. data/lib/couchrest/mixins/views.rb +211 -0
  40. data/lib/couchrest/monkeypatches.rb +112 -0
  41. data/lib/couchrest/more/casted_model.rb +29 -0
  42. data/lib/couchrest/more/extended_document.rb +232 -0
  43. data/lib/couchrest/more/property.rb +40 -0
  44. data/lib/couchrest/support/blank.rb +42 -0
  45. data/lib/couchrest/support/class.rb +176 -0
  46. data/lib/couchrest/support/rails.rb +35 -0
  47. data/lib/couchrest/validation/auto_validate.rb +161 -0
  48. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  49. data/lib/couchrest/validation/validation_errors.rb +118 -0
  50. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  51. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  52. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  53. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  54. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  55. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  56. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  57. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  58. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  59. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  60. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  61. data/spec/couchrest/core/database_spec.rb +700 -0
  62. data/spec/couchrest/core/design_spec.rb +138 -0
  63. data/spec/couchrest/core/document_spec.rb +267 -0
  64. data/spec/couchrest/core/server_spec.rb +35 -0
  65. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  66. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  67. data/spec/couchrest/more/casted_extended_doc_spec.rb +75 -0
  68. data/spec/couchrest/more/casted_model_spec.rb +177 -0
  69. data/spec/couchrest/more/extended_doc_attachment_spec.rb +135 -0
  70. data/spec/couchrest/more/extended_doc_spec.rb +563 -0
  71. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  72. data/spec/couchrest/more/extended_doc_view_spec.rb +414 -0
  73. data/spec/couchrest/more/property_spec.rb +146 -0
  74. data/spec/fixtures/attachments/README +3 -0
  75. data/spec/fixtures/attachments/couchdb.png +0 -0
  76. data/spec/fixtures/attachments/test.html +11 -0
  77. data/spec/fixtures/more/article.rb +34 -0
  78. data/spec/fixtures/more/card.rb +22 -0
  79. data/spec/fixtures/more/cat.rb +18 -0
  80. data/spec/fixtures/more/course.rb +14 -0
  81. data/spec/fixtures/more/event.rb +6 -0
  82. data/spec/fixtures/more/invoice.rb +17 -0
  83. data/spec/fixtures/more/person.rb +8 -0
  84. data/spec/fixtures/more/question.rb +6 -0
  85. data/spec/fixtures/more/service.rb +12 -0
  86. data/spec/fixtures/views/lib.js +3 -0
  87. data/spec/fixtures/views/test_view/lib.js +3 -0
  88. data/spec/fixtures/views/test_view/only-map.js +4 -0
  89. data/spec/fixtures/views/test_view/test-map.js +3 -0
  90. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  91. data/spec/spec.opts +6 -0
  92. data/spec/spec_helper.rb +37 -0
  93. data/utils/remap.rb +27 -0
  94. data/utils/subset.rb +30 -0
  95. metadata +194 -0
@@ -0,0 +1,146 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+ require File.join(FIXTURE_PATH, 'more', 'person')
3
+ require File.join(FIXTURE_PATH, 'more', 'card')
4
+ require File.join(FIXTURE_PATH, 'more', 'invoice')
5
+ require File.join(FIXTURE_PATH, 'more', 'service')
6
+ require File.join(FIXTURE_PATH, 'more', 'event')
7
+
8
+
9
+ describe "ExtendedDocument properties" do
10
+
11
+ before(:each) do
12
+ reset_test_db!
13
+ @card = Card.new(:first_name => "matt")
14
+ end
15
+
16
+ it "should be accessible from the object" do
17
+ @card.properties.should be_an_instance_of(Array)
18
+ @card.properties.map{|p| p.name}.should include("first_name")
19
+ end
20
+
21
+ it "should let you access a property value (getter)" do
22
+ @card.first_name.should == "matt"
23
+ end
24
+
25
+ it "should let you set a property value (setter)" do
26
+ @card.last_name = "Aimonetti"
27
+ @card.last_name.should == "Aimonetti"
28
+ end
29
+
30
+ it "should not let you set a property value if it's read only" do
31
+ lambda{@card.read_only_value = "test"}.should raise_error
32
+ end
33
+
34
+ it "should let you use an alias for an attribute" do
35
+ @card.last_name = "Aimonetti"
36
+ @card.family_name.should == "Aimonetti"
37
+ @card.family_name.should == @card.last_name
38
+ end
39
+
40
+ it "should let you use an alias for a casted attribute" do
41
+ @card.cast_alias = Person.new(:name => "Aimonetti")
42
+ @card.cast_alias.name.should == "Aimonetti"
43
+ @card.calias.name.should == "Aimonetti"
44
+ card = Card.new(:first_name => "matt", :cast_alias => {:name => "Aimonetti"})
45
+ card.cast_alias.name.should == "Aimonetti"
46
+ card.calias.name.should == "Aimonetti"
47
+ end
48
+
49
+ it "should be auto timestamped" do
50
+ @card.created_at.should be_nil
51
+ @card.updated_at.should be_nil
52
+ @card.save.should be_true
53
+ @card.created_at.should_not be_nil
54
+ @card.updated_at.should_not be_nil
55
+ end
56
+
57
+ describe "validation" do
58
+ before(:each) do
59
+ @invoice = Invoice.new(:client_name => "matt", :employee_name => "Chris", :location => "San Diego, CA")
60
+ end
61
+
62
+ it "should be able to be validated" do
63
+ @card.valid?.should == true
64
+ end
65
+
66
+ it "should let you validate the presence of an attribute" do
67
+ @card.first_name = nil
68
+ @card.should_not be_valid
69
+ @card.errors.should_not be_empty
70
+ @card.errors.on(:first_name).should == ["First name must not be blank"]
71
+ end
72
+
73
+ it "should let you look up errors for a field by a string name" do
74
+ @card.first_name = nil
75
+ @card.should_not be_valid
76
+ @card.errors.on('first_name').should == ["First name must not be blank"]
77
+ end
78
+
79
+ it "should validate the presence of 2 attributes" do
80
+ @invoice.clear
81
+ @invoice.should_not be_valid
82
+ @invoice.errors.should_not be_empty
83
+ @invoice.errors.on(:client_name).first.should == "Client name must not be blank"
84
+ @invoice.errors.on(:employee_name).should_not be_empty
85
+ end
86
+
87
+ it "should let you set an error message" do
88
+ @invoice.location = nil
89
+ @invoice.valid?
90
+ @invoice.errors.on(:location).should == ["Hey stupid!, you forgot the location"]
91
+ end
92
+
93
+ it "should validate before saving" do
94
+ @invoice.location = nil
95
+ @invoice.should_not be_valid
96
+ @invoice.save.should be_false
97
+ @invoice.should be_new_document
98
+ end
99
+ end
100
+
101
+ describe "autovalidation" do
102
+ before(:each) do
103
+ @service = Service.new(:name => "Coumpound analysis", :price => 3_000)
104
+ end
105
+
106
+ it "should be valid" do
107
+ @service.should be_valid
108
+ end
109
+
110
+ it "should not respond to properties not setup" do
111
+ @service.respond_to?(:client_name).should be_false
112
+ end
113
+
114
+ describe "property :name, :length => 4...20" do
115
+
116
+ it "should autovalidate the presence when length is set" do
117
+ @service.name = nil
118
+ @service.should_not be_valid
119
+ @service.errors.should_not be_nil
120
+ @service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
121
+ end
122
+
123
+ it "should autovalidate the correct length" do
124
+ @service.name = "a"
125
+ @service.should_not be_valid
126
+ @service.errors.should_not be_nil
127
+ @service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "casting" do
133
+ describe "cast keys to any type" do
134
+ before(:all) do
135
+ event_doc = { :subject => "Some event", :occurs_at => Time.now }
136
+ e = Event.database.save_doc event_doc
137
+
138
+ @event = Event.get e['id']
139
+ end
140
+ it "should cast created_at to Time" do
141
+ @event['occurs_at'].should be_an_instance_of(Time)
142
+ end
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,3 @@
1
+ This is an example README file.
2
+
3
+ More of the README, whee.
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test</title>
5
+ </head>
6
+ <body>
7
+ <p>
8
+ Test
9
+ </p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,34 @@
1
+ class Article < CouchRest::ExtendedDocument
2
+ use_database DB
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
@@ -0,0 +1,22 @@
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 DB
9
+
10
+ # Official Schema
11
+ property :first_name
12
+ property :last_name, :alias => :family_name
13
+ property :read_only_value, :read_only => true
14
+ property :cast_alias, :cast_as => 'Person', :alias => :calias
15
+
16
+
17
+ timestamps!
18
+
19
+ # Validation
20
+ validates_present :first_name
21
+
22
+ end
@@ -0,0 +1,18 @@
1
+ class Cat < CouchRest::ExtendedDocument
2
+ include ::CouchRest::Validation
3
+
4
+ # Set the default database to use
5
+ use_database DB
6
+
7
+ property :name
8
+ property :toys, :cast_as => ['CatToy'], :default => []
9
+ end
10
+
11
+ class CatToy < Hash
12
+ include ::CouchRest::CastedModel
13
+ include ::CouchRest::Validation
14
+
15
+ property :name
16
+
17
+ validates_present :name
18
+ end
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,6 @@
1
+ class Event < CouchRest::ExtendedDocument
2
+ use_database DB
3
+
4
+ property :subject
5
+ property :occurs_at, :cast_as => 'Time', :send => 'parse'
6
+ end
@@ -0,0 +1,17 @@
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 DB
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
@@ -0,0 +1,8 @@
1
+ class Person < Hash
2
+ include ::CouchRest::CastedModel
3
+ property :name
4
+
5
+ def last_name
6
+ name.last
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class Question < Hash
2
+ include ::CouchRest::CastedModel
3
+
4
+ property :q
5
+ property :a
6
+ end
@@ -0,0 +1,12 @@
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 DB
7
+
8
+ # Official Schema
9
+ property :name, :length => 4...20
10
+ property :price, :type => Integer
11
+
12
+ end
@@ -0,0 +1,3 @@
1
+ function globalLib() {
2
+ return "fixture";
3
+ };
@@ -0,0 +1,3 @@
1
+ function justThisView() {
2
+ return "fixture";
3
+ };
@@ -0,0 +1,4 @@
1
+ function(doc) {
2
+ //include-lib
3
+ emit(null, null);
4
+ };
@@ -0,0 +1,3 @@
1
+ function(doc) {
2
+ emit(null, null);
3
+ };
@@ -0,0 +1,3 @@
1
+ function(ks,vs,co) {
2
+ return vs.length;
3
+ };
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ require "rubygems"
2
+ require "spec" # Satisfies Autotest and anyone else not using the Rake tasks
3
+
4
+ require File.join(File.dirname(__FILE__), '..','lib','couchrest')
5
+ # check the following file to see how to use the spec'd features.
6
+
7
+ unless defined?(FIXTURE_PATH)
8
+ FIXTURE_PATH = File.join(File.dirname(__FILE__), '/fixtures')
9
+ SCRATCH_PATH = File.join(File.dirname(__FILE__), '/tmp')
10
+
11
+ COUCHHOST = "http://127.0.0.1:5984"
12
+ TESTDB = 'couchrest-test'
13
+ TEST_SERVER = CouchRest.new
14
+ TEST_SERVER.default_database = TESTDB
15
+ DB = TEST_SERVER.database(TESTDB)
16
+ end
17
+
18
+ class Basic < CouchRest::ExtendedDocument
19
+ use_database TEST_SERVER.default_database
20
+ end
21
+
22
+ def reset_test_db!
23
+ DB.recreate! rescue nil
24
+ DB
25
+ end
26
+
27
+ Spec::Runner.configure do |config|
28
+ config.before(:all) { reset_test_db! }
29
+
30
+ config.after(:all) do
31
+ cr = TEST_SERVER
32
+ test_dbs = cr.databases.select { |db| db =~ /^#{TESTDB}/ }
33
+ test_dbs.each do |db|
34
+ cr.database(db).delete! rescue nil
35
+ end
36
+ end
37
+ end
data/utils/remap.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'couchrest'
3
+
4
+ # set the source db and map view
5
+ source = CouchRest.new("http://127.0.0.1:5984").database('source-db')
6
+ source_view = 'mydesign/view-map'
7
+
8
+ # set the target db
9
+ target = CouchRest.new("http://127.0.0.1:5984").database('target-db')
10
+
11
+
12
+ pager = CouchRest::Pager.new(source)
13
+
14
+ # pager will yield once per uniq key in the source view
15
+
16
+ pager.key_reduce(source_view, 10000) do |key, values|
17
+ # create a doc from the key and the values
18
+ example_doc = {
19
+ :key => key,
20
+ :values => values.uniq
21
+ }
22
+
23
+ target.save(example_doc)
24
+
25
+ # keep us up to date with progress
26
+ puts k if (rand > 0.9)
27
+ end
data/utils/subset.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'couchrest'
3
+
4
+ # subset.rb replicates a percentage of a database to a fresh database.
5
+ # use it to create a smaller dataset on which to prototype views.
6
+
7
+ # specify the source database
8
+ source = CouchRest.new("http://127.0.0.1:5984").database('source-db')
9
+
10
+ # specify the target database
11
+ target = CouchRest.new("http://127.0.0.1:5984").database('target-db')
12
+
13
+ # pager efficiently yields all view rows
14
+ pager = CouchRest::Pager.new(source)
15
+
16
+ pager.all_docs(1000) do |rows|
17
+ docs = rows.collect do |r|
18
+ # the percentage of docs to clone
19
+ next if rand > 0.1
20
+ doc = source.get(r['id'])
21
+ doc.delete('_rev')
22
+ doc
23
+ end.compact
24
+ puts docs.length
25
+ next if docs.empty?
26
+
27
+ puts docs.first['_id']
28
+ target.bulk_save(docs)
29
+ end
30
+