norr-couchrest 0.30

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +117 -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/history.txt +19 -0
  17. data/lib/couchrest.rb +198 -0
  18. data/lib/couchrest/commands/generate.rb +71 -0
  19. data/lib/couchrest/commands/push.rb +103 -0
  20. data/lib/couchrest/core/database.rb +320 -0
  21. data/lib/couchrest/core/design.rb +79 -0
  22. data/lib/couchrest/core/document.rb +87 -0
  23. data/lib/couchrest/core/response.rb +16 -0
  24. data/lib/couchrest/core/server.rb +88 -0
  25. data/lib/couchrest/core/view.rb +4 -0
  26. data/lib/couchrest/helper/pager.rb +103 -0
  27. data/lib/couchrest/helper/streamer.rb +44 -0
  28. data/lib/couchrest/helper/upgrade.rb +51 -0
  29. data/lib/couchrest/mixins.rb +4 -0
  30. data/lib/couchrest/mixins/attachments.rb +31 -0
  31. data/lib/couchrest/mixins/callbacks.rb +483 -0
  32. data/lib/couchrest/mixins/class_proxy.rb +112 -0
  33. data/lib/couchrest/mixins/collection.rb +220 -0
  34. data/lib/couchrest/mixins/design_doc.rb +101 -0
  35. data/lib/couchrest/mixins/document_queries.rb +53 -0
  36. data/lib/couchrest/mixins/extended_attachments.rb +74 -0
  37. data/lib/couchrest/mixins/extended_document_mixins.rb +8 -0
  38. data/lib/couchrest/mixins/properties.rb +147 -0
  39. data/lib/couchrest/mixins/validation.rb +257 -0
  40. data/lib/couchrest/mixins/views.rb +181 -0
  41. data/lib/couchrest/monkeypatches.rb +113 -0
  42. data/lib/couchrest/more/casted_model.rb +29 -0
  43. data/lib/couchrest/more/extended_document.rb +229 -0
  44. data/lib/couchrest/more/property.rb +40 -0
  45. data/lib/couchrest/support/blank.rb +42 -0
  46. data/lib/couchrest/support/class.rb +176 -0
  47. data/lib/couchrest/support/rails.rb +35 -0
  48. data/lib/couchrest/validation/auto_validate.rb +161 -0
  49. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  50. data/lib/couchrest/validation/validation_errors.rb +118 -0
  51. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  52. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  53. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  54. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  55. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  56. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  57. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  58. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  59. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  60. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  61. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  62. data/spec/couchrest/core/database_spec.rb +700 -0
  63. data/spec/couchrest/core/design_spec.rb +138 -0
  64. data/spec/couchrest/core/document_spec.rb +267 -0
  65. data/spec/couchrest/core/server_spec.rb +35 -0
  66. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  67. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  68. data/spec/couchrest/more/casted_extended_doc_spec.rb +75 -0
  69. data/spec/couchrest/more/casted_model_spec.rb +177 -0
  70. data/spec/couchrest/more/extended_doc_attachment_spec.rb +135 -0
  71. data/spec/couchrest/more/extended_doc_spec.rb +563 -0
  72. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  73. data/spec/couchrest/more/extended_doc_view_spec.rb +414 -0
  74. data/spec/couchrest/more/property_spec.rb +146 -0
  75. data/spec/fixtures/attachments/README +3 -0
  76. data/spec/fixtures/attachments/couchdb.png +0 -0
  77. data/spec/fixtures/attachments/test.html +11 -0
  78. data/spec/fixtures/more/article.rb +34 -0
  79. data/spec/fixtures/more/card.rb +22 -0
  80. data/spec/fixtures/more/cat.rb +18 -0
  81. data/spec/fixtures/more/course.rb +14 -0
  82. data/spec/fixtures/more/event.rb +6 -0
  83. data/spec/fixtures/more/invoice.rb +17 -0
  84. data/spec/fixtures/more/person.rb +8 -0
  85. data/spec/fixtures/more/question.rb +6 -0
  86. data/spec/fixtures/more/service.rb +12 -0
  87. data/spec/fixtures/views/lib.js +3 -0
  88. data/spec/fixtures/views/test_view/lib.js +3 -0
  89. data/spec/fixtures/views/test_view/only-map.js +4 -0
  90. data/spec/fixtures/views/test_view/test-map.js +3 -0
  91. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  92. data/spec/spec.opts +6 -0
  93. data/spec/spec_helper.rb +37 -0
  94. data/utils/remap.rb +27 -0
  95. data/utils/subset.rb +30 -0
  96. 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
+