couchrest 0.35 → 0.36

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.
@@ -0,0 +1,180 @@
1
+ require 'time'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/util'
4
+ require File.join(File.dirname(__FILE__), '..', 'more', 'property')
5
+
6
+ class Time
7
+ # returns a local time value much faster than Time.parse
8
+ def self.mktime_with_offset(string)
9
+ string =~ /(\d{4})[\-|\/](\d{2})[\-|\/](\d{2})[T|\s](\d{2}):(\d{2}):(\d{2})([\+|\s|\-])*(\d{2}):?(\d{2})/
10
+ # $1 = year
11
+ # $2 = month
12
+ # $3 = day
13
+ # $4 = hours
14
+ # $5 = minutes
15
+ # $6 = seconds
16
+ # $7 = time zone direction
17
+ # $8 = tz difference
18
+ # utc time with wrong TZ info:
19
+ time = mktime($1, RFC2822_MONTH_NAME[$2.to_i - 1], $3, $4, $5, $6, $7)
20
+ tz_difference = ("#{$7 == '-' ? '+' : '-'}#{$8}".to_i * 3600)
21
+ time + tz_difference + zone_offset(time.zone)
22
+ end
23
+ end
24
+
25
+ module CouchRest
26
+ module More
27
+ module Typecast
28
+
29
+ def typecast_value(value, klass, init_method)
30
+ return nil if value.nil?
31
+
32
+ if value.instance_of?(klass) || klass.to_s == 'Object'
33
+ value
34
+ elsif ['String', 'TrueClass', 'Integer', 'Float', 'BigDecimal', 'DateTime', 'Time', 'Date', 'Class'].include?(klass.to_s)
35
+ send('typecast_to_'+klass.to_s.downcase, value)
36
+ else
37
+ # Allow the init_method to be defined as a Proc for advanced conversion
38
+ init_method.is_a?(Proc) ? init_method.call(value) : klass.send(init_method, value)
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ # Typecast a value to an Integer
45
+ def typecast_to_integer(value)
46
+ value.kind_of?(Integer) ? value : typecast_to_numeric(value, :to_i)
47
+ end
48
+
49
+ # Typecast a value to a String
50
+ def typecast_to_string(value)
51
+ value.to_s
52
+ end
53
+
54
+ # Typecast a value to a true or false
55
+ def typecast_to_trueclass(value)
56
+ if value.kind_of?(Integer)
57
+ return true if value == 1
58
+ return false if value == 0
59
+ elsif value.respond_to?(:to_s)
60
+ return true if %w[ true 1 t ].include?(value.to_s.downcase)
61
+ return false if %w[ false 0 f ].include?(value.to_s.downcase)
62
+ end
63
+ value
64
+ end
65
+
66
+ # Typecast a value to a BigDecimal
67
+ def typecast_to_bigdecimal(value)
68
+ return value if value.kind_of?(BigDecimal)
69
+
70
+ if value.kind_of?(Integer)
71
+ value.to_s.to_d
72
+ else
73
+ typecast_to_numeric(value, :to_d)
74
+ end
75
+ end
76
+
77
+ # Typecast a value to a Float
78
+ def typecast_to_float(value)
79
+ return value if value.kind_of?(Float)
80
+ typecast_to_numeric(value, :to_f)
81
+ end
82
+
83
+ # Match numeric string
84
+ def typecast_to_numeric(value, method)
85
+ if value.respond_to?(:to_str)
86
+ if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/
87
+ $1.send(method)
88
+ else
89
+ value
90
+ end
91
+ elsif value.respond_to?(method)
92
+ value.send(method)
93
+ else
94
+ value
95
+ end
96
+ end
97
+
98
+ # Typecasts an arbitrary value to a DateTime.
99
+ # Handles both Hashes and DateTime instances.
100
+ def typecast_to_datetime(value)
101
+ return value if value.kind_of?(DateTime)
102
+
103
+ if value.is_a?(Hash)
104
+ typecast_hash_to_datetime(value)
105
+ else
106
+ DateTime.parse(value.to_s)
107
+ end
108
+ rescue ArgumentError
109
+ value
110
+ end
111
+
112
+ # Typecasts an arbitrary value to a Date
113
+ # Handles both Hashes and Date instances.
114
+ def typecast_to_date(value)
115
+ return value if value.kind_of?(Date)
116
+
117
+ if value.is_a?(Hash)
118
+ typecast_hash_to_date(value)
119
+ else
120
+ Date.parse(value.to_s)
121
+ end
122
+ rescue ArgumentError
123
+ value
124
+ end
125
+
126
+ # Typecasts an arbitrary value to a Time
127
+ # Handles both Hashes and Time instances.
128
+ def typecast_to_time(value)
129
+ return value if value.kind_of?(Time)
130
+
131
+ if value.is_a?(Hash)
132
+ typecast_hash_to_time(value)
133
+ else
134
+ Time.mktime_with_offset(value.to_s)
135
+ end
136
+ rescue ArgumentError
137
+ value
138
+ rescue TypeError
139
+ value
140
+ end
141
+
142
+ # Creates a DateTime instance from a Hash with keys :year, :month, :day,
143
+ # :hour, :min, :sec
144
+ def typecast_hash_to_datetime(value)
145
+ DateTime.new(*extract_time(value))
146
+ end
147
+
148
+ # Creates a Date instance from a Hash with keys :year, :month, :day
149
+ def typecast_hash_to_date(value)
150
+ Date.new(*extract_time(value)[0, 3])
151
+ end
152
+
153
+ # Creates a Time instance from a Hash with keys :year, :month, :day,
154
+ # :hour, :min, :sec
155
+ def typecast_hash_to_time(value)
156
+ Time.local(*extract_time(value))
157
+ end
158
+
159
+ # Extracts the given args from the hash. If a value does not exist, it
160
+ # uses the value of Time.now.
161
+ def extract_time(value)
162
+ now = Time.now
163
+
164
+ [:year, :month, :day, :hour, :min, :sec].map do |segment|
165
+ typecast_to_numeric(value.fetch(segment, now.send(segment)), :to_i)
166
+ end
167
+ end
168
+
169
+ # Typecast a value to a Class
170
+ def typecast_to_class(value)
171
+ return value if value.kind_of?(Class)
172
+ ::CouchRest.constantize(value.to_s)
173
+ rescue NameError
174
+ value
175
+ end
176
+
177
+ end
178
+ end
179
+ end
180
+
@@ -37,7 +37,7 @@ module CouchRest
37
37
 
38
38
  def call(target)
39
39
  value = target.validation_property_value(field_name)
40
- property = target.validation_property(field_name)
40
+ property = target.validation_property(field_name.to_s)
41
41
  return true if present?(value, property)
42
42
 
43
43
  error_message = @options[:message] || default_error(property)
@@ -66,7 +66,7 @@ module CouchRest
66
66
  # Returns false for other property types.
67
67
  # Returns false for non-properties.
68
68
  def boolean_type?(property)
69
- property ? property.type == TrueClass : false
69
+ property ? property.type == 'Boolean' : false
70
70
  end
71
71
 
72
72
  end # class RequiredFieldValidator
@@ -46,137 +46,74 @@ describe CouchRest do
46
46
  it "should parse just a dbname" do
47
47
  db = CouchRest.parse "my-db"
48
48
  db[:database].should == "my-db"
49
- db[:host].should == "127.0.0.1:5984"
49
+ db[:host].should == "http://127.0.0.1:5984"
50
50
  end
51
51
  it "should parse a host and db" do
52
52
  db = CouchRest.parse "127.0.0.1/my-db"
53
53
  db[:database].should == "my-db"
54
- db[:host].should == "127.0.0.1"
55
- end
56
- it "should parse a host and db with http" do
57
- db = CouchRest.parse "https://127.0.0.1/my-db"
58
- db[:database].should == "my-db"
59
- db[:host].should == "127.0.0.1"
60
- end
61
- it "should parse a host with a port and db" do
62
- db = CouchRest.parse "127.0.0.1:5555/my-db"
63
- db[:database].should == "my-db"
64
- db[:host].should == "127.0.0.1:5555"
65
- end
66
- it "should parse a host with a port and db with http" do
67
- db = CouchRest.parse "http://127.0.0.1:5555/my-db"
68
- db[:database].should == "my-db"
69
- db[:host].should == "127.0.0.1:5555"
70
- end
71
- it "should parse a host with a port and db with https" do
72
- db = CouchRest.parse "https://127.0.0.1:5555/my-db"
73
- db[:database].should == "my-db"
74
- db[:host].should == "127.0.0.1:5555"
75
- end
76
- it "should parse just a host" do
77
- db = CouchRest.parse "http://127.0.0.1:5555/"
78
- db[:database].should be_nil
79
- db[:host].should == "127.0.0.1:5555"
80
- end
81
- it "should parse just a host with https" do
82
- db = CouchRest.parse "https://127.0.0.1:5555/"
83
- db[:database].should be_nil
84
- db[:host].should == "127.0.0.1:5555"
85
- end
86
- it "should parse just a host no slash" do
87
- db = CouchRest.parse "http://127.0.0.1:5555"
88
- db[:host].should == "127.0.0.1:5555"
89
- db[:database].should be_nil
90
- end
91
- it "should parse just a host no slash and https" do
92
- db = CouchRest.parse "https://127.0.0.1:5555"
93
- db[:host].should == "127.0.0.1:5555"
94
- db[:database].should be_nil
95
- end
96
- it "should get docid" do
97
- db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc"
98
- db[:database].should == "my-db"
99
- db[:host].should == "127.0.0.1:5555"
100
- db[:doc].should == "my-doc"
101
- end
102
- it "should get docid with http" do
103
- db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc"
104
- db[:database].should == "my-db"
105
- db[:host].should == "127.0.0.1:5555"
106
- db[:doc].should == "my-doc"
107
- end
108
- it "should get docid with https" do
109
- db = CouchRest.parse "https://127.0.0.1:5555/my-db/my-doc"
110
- db[:database].should == "my-db"
111
- db[:host].should == "127.0.0.1:5555"
112
- db[:doc].should == "my-doc"
113
- end
114
- it "should parse a host and db" do
115
- db = CouchRest.parse "127.0.0.1/my-db"
116
- db[:database].should == "my-db"
117
- db[:host].should == "127.0.0.1"
54
+ db[:host].should == "http://127.0.0.1"
118
55
  end
119
56
  it "should parse a host and db with http" do
120
57
  db = CouchRest.parse "http://127.0.0.1/my-db"
121
58
  db[:database].should == "my-db"
122
- db[:host].should == "127.0.0.1"
59
+ db[:host].should == "http://127.0.0.1"
123
60
  end
124
61
  it "should parse a host and db with https" do
125
62
  db = CouchRest.parse "https://127.0.0.1/my-db"
126
63
  db[:database].should == "my-db"
127
- db[:host].should == "127.0.0.1"
64
+ db[:host].should == "https://127.0.0.1"
128
65
  end
129
66
  it "should parse a host with a port and db" do
130
67
  db = CouchRest.parse "127.0.0.1:5555/my-db"
131
68
  db[:database].should == "my-db"
132
- db[:host].should == "127.0.0.1:5555"
69
+ db[:host].should == "http://127.0.0.1:5555"
133
70
  end
134
71
  it "should parse a host with a port and db with http" do
135
72
  db = CouchRest.parse "http://127.0.0.1:5555/my-db"
136
73
  db[:database].should == "my-db"
137
- db[:host].should == "127.0.0.1:5555"
74
+ db[:host].should == "http://127.0.0.1:5555"
138
75
  end
139
76
  it "should parse a host with a port and db with https" do
140
- db = CouchRest.parse "http://127.0.0.1:5555/my-db"
77
+ db = CouchRest.parse "https://127.0.0.1:5555/my-db"
141
78
  db[:database].should == "my-db"
142
- db[:host].should == "127.0.0.1:5555"
79
+ db[:host].should == "https://127.0.0.1:5555"
143
80
  end
144
81
  it "should parse just a host" do
145
82
  db = CouchRest.parse "http://127.0.0.1:5555/"
146
83
  db[:database].should be_nil
147
- db[:host].should == "127.0.0.1:5555"
84
+ db[:host].should == "http://127.0.0.1:5555"
148
85
  end
149
86
  it "should parse just a host with https" do
150
87
  db = CouchRest.parse "https://127.0.0.1:5555/"
151
88
  db[:database].should be_nil
152
- db[:host].should == "127.0.0.1:5555"
89
+ db[:host].should == "https://127.0.0.1:5555"
153
90
  end
154
91
  it "should parse just a host no slash" do
155
92
  db = CouchRest.parse "http://127.0.0.1:5555"
156
- db[:host].should == "127.0.0.1:5555"
93
+ db[:host].should == "http://127.0.0.1:5555"
157
94
  db[:database].should be_nil
158
95
  end
159
96
  it "should parse just a host no slash and https" do
160
97
  db = CouchRest.parse "https://127.0.0.1:5555"
161
- db[:host].should == "127.0.0.1:5555"
98
+ db[:host].should == "https://127.0.0.1:5555"
162
99
  db[:database].should be_nil
163
100
  end
164
101
  it "should get docid" do
165
102
  db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc"
166
103
  db[:database].should == "my-db"
167
- db[:host].should == "127.0.0.1:5555"
104
+ db[:host].should == "http://127.0.0.1:5555"
168
105
  db[:doc].should == "my-doc"
169
106
  end
170
107
  it "should get docid with http" do
171
108
  db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc"
172
109
  db[:database].should == "my-db"
173
- db[:host].should == "127.0.0.1:5555"
110
+ db[:host].should == "http://127.0.0.1:5555"
174
111
  db[:doc].should == "my-doc"
175
112
  end
176
113
  it "should get docid with https" do
177
114
  db = CouchRest.parse "https://127.0.0.1:5555/my-db/my-doc"
178
115
  db[:database].should == "my-db"
179
- db[:host].should == "127.0.0.1:5555"
116
+ db[:host].should == "https://127.0.0.1:5555"
180
117
  db[:doc].should == "my-doc"
181
118
  end
182
119
  end
@@ -185,7 +122,7 @@ describe CouchRest do
185
122
  it "should be possible without an explicit CouchRest instantiation" do
186
123
  db = CouchRest.database "http://127.0.0.1:5984/couchrest-test"
187
124
  db.should be_an_instance_of(CouchRest::Database)
188
- db.host.should == "127.0.0.1:5984"
125
+ db.host.should == "http://127.0.0.1:5984"
189
126
  end
190
127
  # TODO add https support (need test environment...)
191
128
  # it "should work with https" # do
@@ -703,12 +703,12 @@ describe CouchRest::Database do
703
703
  end
704
704
  end
705
705
 
706
- describe "replicating a database" do
706
+ describe "simply replicating a database" do
707
707
  before do
708
708
  @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
709
- @other_db = @cr.database 'couchrest-test-replication'
709
+ @other_db = @cr.database REPLICATIONDB
710
710
  @other_db.delete! rescue nil
711
- @other_db = @cr.create_db 'couchrest-test-replication'
711
+ @other_db = @cr.create_db REPLICATIONDB
712
712
  end
713
713
 
714
714
  describe "via pulling" do
@@ -733,6 +733,53 @@ describe CouchRest::Database do
733
733
  end
734
734
  end
735
735
  end
736
+
737
+ describe "continuously replicating a database" do
738
+ before do
739
+ @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
740
+ @other_db = @cr.database REPLICATIONDB
741
+ @other_db.delete! rescue nil
742
+ @other_db = @cr.create_db REPLICATIONDB
743
+ end
744
+
745
+ describe "via pulling" do
746
+ before do
747
+ @other_db.replicate_from @db, true
748
+ end
749
+
750
+ it "contains the document from the original database" do
751
+ sleep(1) # Allow some time to replicate
752
+ doc = @other_db.get('test_doc')
753
+ doc['some-value'].should == 'foo'
754
+ end
755
+
756
+ it "contains documents saved after replication initiated" do
757
+ @db.save_doc({'_id' => 'test_doc_after', 'some-value' => 'bar'})
758
+ sleep(1) # Allow some time to replicate
759
+ doc = @other_db.get('test_doc_after')
760
+ doc['some-value'].should == 'bar'
761
+ end
762
+ end
763
+
764
+ describe "via pushing" do
765
+ before do
766
+ @db.replicate_to @other_db, true
767
+ end
768
+
769
+ it "copies the document to the other database" do
770
+ sleep(1) # Allow some time to replicate
771
+ doc = @other_db.get('test_doc')
772
+ doc['some-value'].should == 'foo'
773
+ end
774
+
775
+ it "copies documents saved after replication initiated" do
776
+ @db.save_doc({'_id' => 'test_doc_after', 'some-value' => 'bar'})
777
+ sleep(1) # Allow some time to replicate
778
+ doc = @other_db.get('test_doc_after')
779
+ doc['some-value'].should == 'bar'
780
+ end
781
+ end
782
+ end
736
783
 
737
784
  describe "creating a database" do
738
785
  before(:each) do
@@ -769,5 +816,25 @@ describe CouchRest::Database do
769
816
 
770
817
  end
771
818
 
819
+ describe "searching a database" do
820
+ before(:each) do
821
+ search_function = { 'defaults' => {'store' => 'no', 'index' => 'analyzed_no_norms'},
822
+ 'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); ret.add(doc['age'], {'field':'age'}); return ret; }" }
823
+ @db.save_doc({'_id' => '_design/search', 'fulltext' => {'people' => search_function}})
824
+ @db.save_doc({'_id' => 'john', 'name' => 'John', 'age' => '31'})
825
+ @db.save_doc({'_id' => 'jack', 'name' => 'Jack', 'age' => '32'})
826
+ @db.save_doc({'_id' => 'dave', 'name' => 'Dave', 'age' => '33'})
827
+ end
828
+
829
+ it "should be able to search a database using couchdb-lucene" do
830
+ if couchdb_lucene_available?
831
+ result = @db.search('search/people', :q => 'name:J*')
832
+ doc_ids = result['rows'].collect{ |row| row['id'] }
833
+ doc_ids.size.should == 2
834
+ doc_ids.should include('john')
835
+ doc_ids.should include('jack')
836
+ end
837
+ end
838
+ end
772
839
 
773
840
  end