ripple 0.8.2 → 0.8.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.
- data/Gemfile +16 -0
- data/Rakefile +115 -16
- data/lib/rails/generators/ripple/configuration/configuration_generator.rb +26 -0
- data/lib/rails/generators/ripple/configuration/templates/ripple.yml +21 -0
- data/lib/rails/generators/ripple/js/js_generator.rb +26 -0
- data/lib/rails/generators/ripple/js/templates/js/contrib.js +80 -0
- data/lib/rails/generators/ripple/js/templates/js/ripple.js +145 -0
- data/lib/rails/generators/ripple/model/model_generator.rb +1 -1
- data/lib/rails/generators/ripple/test/templates/test_server.rb +42 -0
- data/lib/rails/generators/ripple/test/test_generator.rb +52 -0
- data/lib/rails/generators/ripple_generator.rb +15 -1
- data/lib/ripple.rb +1 -0
- data/lib/ripple/associations.rb +1 -1
- data/lib/ripple/attribute_methods.rb +2 -1
- data/lib/ripple/attribute_methods/dirty.rb +1 -1
- data/lib/ripple/core_ext/casting.rb +22 -8
- data/lib/ripple/document/finders.rb +5 -6
- data/lib/ripple/document/persistence.rb +1 -1
- data/lib/ripple/railtie.rb +3 -1
- data/lib/ripple/timestamps.rb +2 -2
- data/ripple.gemspec +40 -0
- data/spec/ripple/associations/one_linked_proxy_spec.rb +21 -5
- data/spec/ripple/attribute_methods_spec.rb +13 -1
- data/spec/ripple/core_ext_spec.rb +8 -0
- data/spec/ripple/finders_spec.rb +5 -0
- data/spec/ripple/persistence_spec.rb +6 -4
- data/spec/ripple/properties_spec.rb +32 -3
- data/spec/support/models/widget.rb +3 -0
- data/spec/support/test_server.yml.example +2 -0
- metadata +16 -33
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source :gemcutter
|
2
|
+
|
3
|
+
gem 'bundler'
|
4
|
+
gem 'riak-client', :path => "../riak-client"
|
5
|
+
gem 'activemodel', '~>3.0.0'
|
6
|
+
gem 'rspec', '~>2.0.0'
|
7
|
+
gem 'tzinfo'
|
8
|
+
gem 'rake'
|
9
|
+
|
10
|
+
if defined? JRUBY_VERSION
|
11
|
+
gem 'json'
|
12
|
+
gem 'jruby-openssl'
|
13
|
+
else
|
14
|
+
gem 'yajl-ruby'
|
15
|
+
gem 'curb', '>0.6'
|
16
|
+
end
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ gemspec = Gem::Specification.new do |gem|
|
|
8
8
|
gem.summary = %Q{ripple is an object-mapper library for Riak, the distributed database by Basho.}
|
9
9
|
gem.description = %Q{ripple is an object-mapper library for Riak, the distributed database by Basho. It uses ActiveModel to provide an experience that integrates well with Rails 3 applications.}
|
10
10
|
gem.version = version
|
11
|
-
gem.email = "
|
11
|
+
gem.email = "sean@basho.com"
|
12
12
|
gem.homepage = "http://seancribbs.github.com/ripple"
|
13
13
|
gem.authors = ["Sean Cribbs"]
|
14
14
|
gem.add_development_dependency "rspec", "~>2.0.0"
|
@@ -16,22 +16,121 @@ gemspec = Gem::Specification.new do |gem|
|
|
16
16
|
gem.add_dependency "activesupport", "~>3.0.0"
|
17
17
|
gem.add_dependency "activemodel", "~>3.0.0"
|
18
18
|
|
19
|
-
files =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
gem.files = %W{
|
20
|
+
Gemfile
|
21
|
+
lib/rails/generators/ripple/configuration/configuration_generator.rb
|
22
|
+
lib/rails/generators/ripple/configuration/templates
|
23
|
+
lib/rails/generators/ripple/configuration/templates/ripple.yml
|
24
|
+
lib/rails/generators/ripple/js/js_generator.rb
|
25
|
+
lib/rails/generators/ripple/js/templates/js/contrib.js
|
26
|
+
lib/rails/generators/ripple/js/templates/js/ripple.js
|
27
|
+
lib/rails/generators/ripple/model/model_generator.rb
|
28
|
+
lib/rails/generators/ripple/model/templates
|
29
|
+
lib/rails/generators/ripple/model/templates/model.rb
|
30
|
+
lib/rails/generators/ripple/test/templates/test_server.rb
|
31
|
+
lib/rails/generators/ripple/test/test_generator.rb
|
32
|
+
lib/rails/generators/ripple_generator.rb
|
33
|
+
lib/ripple/associations/embedded.rb
|
34
|
+
lib/ripple/associations/instantiators.rb
|
35
|
+
lib/ripple/associations/linked.rb
|
36
|
+
lib/ripple/associations/many.rb
|
37
|
+
lib/ripple/associations/many_embedded_proxy.rb
|
38
|
+
lib/ripple/associations/many_linked_proxy.rb
|
39
|
+
lib/ripple/associations/one.rb
|
40
|
+
lib/ripple/associations/one_embedded_proxy.rb
|
41
|
+
lib/ripple/associations/one_linked_proxy.rb
|
42
|
+
lib/ripple/associations/proxy.rb
|
43
|
+
lib/ripple/associations.rb
|
44
|
+
lib/ripple/attribute_methods/dirty.rb
|
45
|
+
lib/ripple/attribute_methods/query.rb
|
46
|
+
lib/ripple/attribute_methods/read.rb
|
47
|
+
lib/ripple/attribute_methods/write.rb
|
48
|
+
lib/ripple/attribute_methods.rb
|
49
|
+
lib/ripple/callbacks.rb
|
50
|
+
lib/ripple/conversion.rb
|
51
|
+
lib/ripple/core_ext/casting.rb
|
52
|
+
lib/ripple/core_ext.rb
|
53
|
+
lib/ripple/document/bucket_access.rb
|
54
|
+
lib/ripple/document/finders.rb
|
55
|
+
lib/ripple/document/key.rb
|
56
|
+
lib/ripple/document/persistence.rb
|
57
|
+
lib/ripple/document.rb
|
58
|
+
lib/ripple/embedded_document/finders.rb
|
59
|
+
lib/ripple/embedded_document/persistence.rb
|
60
|
+
lib/ripple/embedded_document.rb
|
61
|
+
lib/ripple/i18n.rb
|
62
|
+
lib/ripple/inspection.rb
|
63
|
+
lib/ripple/locale
|
64
|
+
lib/ripple/locale/en.yml
|
65
|
+
lib/ripple/nested_attributes.rb
|
66
|
+
lib/ripple/properties.rb
|
67
|
+
lib/ripple/property_type_mismatch.rb
|
68
|
+
lib/ripple/railtie.rb
|
69
|
+
lib/ripple/timestamps.rb
|
70
|
+
lib/ripple/translation.rb
|
71
|
+
lib/ripple/validations/associated_validator.rb
|
72
|
+
lib/ripple/validations.rb
|
73
|
+
lib/ripple.rb
|
74
|
+
Rakefile
|
75
|
+
ripple.gemspec
|
76
|
+
spec/fixtures/config.yml
|
77
|
+
spec/integration/ripple/associations_spec.rb
|
78
|
+
spec/integration/ripple/nested_attributes_spec.rb
|
79
|
+
spec/integration/ripple/persistence_spec.rb
|
80
|
+
spec/ripple/associations/many_embedded_proxy_spec.rb
|
81
|
+
spec/ripple/associations/many_linked_proxy_spec.rb
|
82
|
+
spec/ripple/associations/one_embedded_proxy_spec.rb
|
83
|
+
spec/ripple/associations/one_linked_proxy_spec.rb
|
84
|
+
spec/ripple/associations/proxy_spec.rb
|
85
|
+
spec/ripple/associations_spec.rb
|
86
|
+
spec/ripple/attribute_methods_spec.rb
|
87
|
+
spec/ripple/bucket_access_spec.rb
|
88
|
+
spec/ripple/callbacks_spec.rb
|
89
|
+
spec/ripple/conversion_spec.rb
|
90
|
+
spec/ripple/core_ext_spec.rb
|
91
|
+
spec/ripple/document_spec.rb
|
92
|
+
spec/ripple/embedded_document/finders_spec.rb
|
93
|
+
spec/ripple/embedded_document/persistence_spec.rb
|
94
|
+
spec/ripple/embedded_document_spec.rb
|
95
|
+
spec/ripple/finders_spec.rb
|
96
|
+
spec/ripple/inspection_spec.rb
|
97
|
+
spec/ripple/key_spec.rb
|
98
|
+
spec/ripple/persistence_spec.rb
|
99
|
+
spec/ripple/properties_spec.rb
|
100
|
+
spec/ripple/ripple_spec.rb
|
101
|
+
spec/ripple/timestamps_spec.rb
|
102
|
+
spec/ripple/validations_spec.rb
|
103
|
+
spec/spec_helper.rb
|
104
|
+
spec/support/associations/proxies.rb
|
105
|
+
spec/support/mocks.rb
|
106
|
+
spec/support/models/address.rb
|
107
|
+
spec/support/models/box.rb
|
108
|
+
spec/support/models/car.rb
|
109
|
+
spec/support/models/cardboard_box.rb
|
110
|
+
spec/support/models/clock.rb
|
111
|
+
spec/support/models/customer.rb
|
112
|
+
spec/support/models/driver.rb
|
113
|
+
spec/support/models/email.rb
|
114
|
+
spec/support/models/engine.rb
|
115
|
+
spec/support/models/family.rb
|
116
|
+
spec/support/models/favorite.rb
|
117
|
+
spec/support/models/invoice.rb
|
118
|
+
spec/support/models/late_invoice.rb
|
119
|
+
spec/support/models/note.rb
|
120
|
+
spec/support/models/page.rb
|
121
|
+
spec/support/models/paid_invoice.rb
|
122
|
+
spec/support/models/passenger.rb
|
123
|
+
spec/support/models/seat.rb
|
124
|
+
spec/support/models/tasks.rb
|
125
|
+
spec/support/models/tree.rb
|
126
|
+
spec/support/models/user.rb
|
127
|
+
spec/support/models/wheel.rb
|
128
|
+
spec/support/models/widget.rb
|
129
|
+
spec/support/test_server.rb
|
130
|
+
spec/support/test_server.yml.example
|
131
|
+
}
|
31
132
|
|
32
|
-
gem.
|
33
|
-
|
34
|
-
gem.test_files = FileList["spec/**/*.rb"].to_a
|
133
|
+
gem.test_files = gem.files.grep(/_spec\.rb$/)
|
35
134
|
end
|
36
135
|
|
37
136
|
# Gem packaging tasks
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'rails/generators/ripple_generator'
|
15
|
+
|
16
|
+
module Ripple
|
17
|
+
module Generators
|
18
|
+
class ConfigurationGenerator < Base
|
19
|
+
desc 'Generates a configuration file for Ripple.'
|
20
|
+
|
21
|
+
def create_configuration_file
|
22
|
+
template 'ripple.yml', 'config/ripple.yml'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Configure Riak connections for the Ripple library.
|
2
|
+
development:
|
3
|
+
port: 8098
|
4
|
+
host: localhost
|
5
|
+
|
6
|
+
# The test environment has additional keys for configuring the
|
7
|
+
# Riak::TestServer for your test/spec suite:
|
8
|
+
#
|
9
|
+
# * bin_dir specifies the path to the "riak" script that you use to
|
10
|
+
# start Riak (just the directory)
|
11
|
+
# * js_source_dir specifies where your custom Javascript functions for
|
12
|
+
# MapReduce should be loaded from. Usually app/mapreduce.
|
13
|
+
test:
|
14
|
+
port: 9000
|
15
|
+
host: localhost
|
16
|
+
bin_dir: /usr/local/bin # Default for Homebrew.
|
17
|
+
js_source_dir: <%%= Rails.root + "app/mapreduce" %>
|
18
|
+
|
19
|
+
production:
|
20
|
+
port: 8098
|
21
|
+
host: localhost
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'rails/generators/ripple_generator'
|
15
|
+
|
16
|
+
module Ripple
|
17
|
+
module Generators
|
18
|
+
class JsGenerator < Base
|
19
|
+
desc 'Generates Javascript built-ins for use in your queries.'
|
20
|
+
|
21
|
+
def create_js_files
|
22
|
+
directory 'js', 'app/mapreduce'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
// -------------------------------------------------------------------
|
2
|
+
//
|
3
|
+
//
|
4
|
+
// This file is provided to you under the Apache License,
|
5
|
+
// Version 2.0 (the "License"); you may not use this file
|
6
|
+
// except in compliance with the License. You may obtain
|
7
|
+
// a copy of the License at
|
8
|
+
//
|
9
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
//
|
11
|
+
// Unless required by applicable law or agreed to in writing,
|
12
|
+
// software distributed under the License is distributed on an
|
13
|
+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
// KIND, either express or implied. See the License for the
|
15
|
+
// specific language governing permissions and limitations
|
16
|
+
// under the License.
|
17
|
+
//
|
18
|
+
// -------------------------------------------------------------------
|
19
|
+
//
|
20
|
+
// This file contains Javascript MapReduce functions copied from the
|
21
|
+
// "Riak Function Contrib" project.
|
22
|
+
//
|
23
|
+
Riak.Contrib = {
|
24
|
+
// Count keys in a group of results.
|
25
|
+
// http://contrib.basho.com/count_keys.html
|
26
|
+
mapCount: function(){
|
27
|
+
return [1];
|
28
|
+
},
|
29
|
+
|
30
|
+
// Generate commonly used statistics from an array of numbers.
|
31
|
+
// Supports count, sum, min, max, percentiles, mean, variance, and
|
32
|
+
// stddev.
|
33
|
+
// http://contrib.basho.com/stats.html
|
34
|
+
reduceStats: function(data) {
|
35
|
+
var result = {};
|
36
|
+
|
37
|
+
data.sort(function(a,b){return a-b;});
|
38
|
+
result.count = data.length;
|
39
|
+
|
40
|
+
// Since the data is sorted, the minimum value
|
41
|
+
// is at the beginning of the array, the median
|
42
|
+
// value is in the middle of the array, and the
|
43
|
+
// maximum value is at the end of the array.
|
44
|
+
result.min = data[0];
|
45
|
+
result.max = data[data.length - 1];
|
46
|
+
|
47
|
+
var ntileFunc = function(percentile){
|
48
|
+
if (data.length == 1) return data[0];
|
49
|
+
var ntileRank = ((percentile/100) * (data.length - 1)) + 1;
|
50
|
+
var integralRank = Math.floor(ntileRank);
|
51
|
+
var fractionalRank = ntileRank - integralRank;
|
52
|
+
var lowerValue = data[integralRank-1];
|
53
|
+
var upperValue = data[integralRank];
|
54
|
+
return (fractionalRank * (upperValue - lowerValue)) + lowerValue;
|
55
|
+
};
|
56
|
+
|
57
|
+
result.percentile25 = ntileFunc(25);
|
58
|
+
result.median = ntileFunc(50);
|
59
|
+
result.percentile75 = ntileFunc(75);
|
60
|
+
result.percentile99 = ntileFunc(99);
|
61
|
+
|
62
|
+
// Compute the mean and variance using a
|
63
|
+
// numerically stable algorithm.
|
64
|
+
var sqsum = 0;
|
65
|
+
result.mean = data[0];
|
66
|
+
result.sum = result.mean * result.count;
|
67
|
+
for (var i = 1; i < data.length; ++i) {
|
68
|
+
var x = data[i];
|
69
|
+
var delta = x - result.mean;
|
70
|
+
var sweep = i + 1.0;
|
71
|
+
result.mean += delta / sweep;
|
72
|
+
sqsum += delta * delta * (i / sweep);
|
73
|
+
result.sum += x;
|
74
|
+
}
|
75
|
+
result.variance = sqsum / result.count;
|
76
|
+
result.sdev = Math.sqrt(result.variance);
|
77
|
+
|
78
|
+
return result;
|
79
|
+
}
|
80
|
+
};
|
@@ -0,0 +1,145 @@
|
|
1
|
+
// Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
+
//
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
// you may not use this file except in compliance with the License.
|
5
|
+
// You may obtain a copy of the License at
|
6
|
+
//
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
//
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
// See the License for the specific language governing permissions and
|
13
|
+
// limitations under the License.
|
14
|
+
|
15
|
+
/*
|
16
|
+
* Namespace for Ripple's built-in MapReduce functions.
|
17
|
+
*/
|
18
|
+
var Ripple = {
|
19
|
+
/*
|
20
|
+
* Filter input values by simple equality test on passed "fields"
|
21
|
+
* argument. Returns bucket/key pairs for use in later map phases.
|
22
|
+
*
|
23
|
+
* Raw Phase Example:
|
24
|
+
* {"map":{
|
25
|
+
* "language":"javascript",
|
26
|
+
* "name":"Ripple.filterByFields",
|
27
|
+
* "arg":{"manufactured":true, "name":"widget"}
|
28
|
+
* }}
|
29
|
+
*
|
30
|
+
* Ruby invocation example:
|
31
|
+
* mr.map("Ripple.filterByFields",
|
32
|
+
* :arg => {:manufactured => true, :name => "widget"})
|
33
|
+
*
|
34
|
+
*/
|
35
|
+
filterByFields: function(value, keyData, fields){
|
36
|
+
var object = Riak.mapValuesJson(value)[0];
|
37
|
+
for(field in fields){
|
38
|
+
if(object[field] != fields[field])
|
39
|
+
return [];
|
40
|
+
}
|
41
|
+
return [[value.bucket, value.key]];
|
42
|
+
},
|
43
|
+
/*
|
44
|
+
* Filter input values by various conditions passed as the
|
45
|
+
* "conditions" argument. Returns bucket/key pairs for use in
|
46
|
+
* later map phases.
|
47
|
+
*
|
48
|
+
* Valid operators:
|
49
|
+
* ==, eq (equality)
|
50
|
+
* !=, neq (inequality)
|
51
|
+
* <, lt (less than)
|
52
|
+
* =<, <=, lte (less than or equal)
|
53
|
+
* >, gt (greater than)
|
54
|
+
* >=, =>, gte (greater than or equal)
|
55
|
+
* ~=, match (regular expression match)
|
56
|
+
* between (inclusive numeric range)
|
57
|
+
* includes (String or Array inclusion)
|
58
|
+
*
|
59
|
+
* Example:
|
60
|
+
* {"map":{
|
61
|
+
* "language":"javascript",
|
62
|
+
* "name":"Ripple.filterByConditions",
|
63
|
+
* "arg":{"tags":{"includes":"riak"}, "title":{"~=":"schema"}}
|
64
|
+
* }}
|
65
|
+
*
|
66
|
+
* Ruby invocation example:
|
67
|
+
* mr.map("Ripple.filterByConditions",
|
68
|
+
* :arg => {:tags => {:includes => "riak"},
|
69
|
+
* :title => {"~=" => "schema"}})
|
70
|
+
*/
|
71
|
+
filterByConditions: function(value, keyData, conditions){
|
72
|
+
var object = Riak.mapValuesJson(value)[0];
|
73
|
+
for(condition in conditions){
|
74
|
+
if(!Ripple.conditionMatch(condition, conditions[condition], object))
|
75
|
+
return [];
|
76
|
+
}
|
77
|
+
return [[value.bucket, value.key]];
|
78
|
+
},
|
79
|
+
/*
|
80
|
+
* Given a specific field and test, returns whether the object
|
81
|
+
* matches the condition specified by the test. Used internally by
|
82
|
+
* Ripple.filterByConditions map phases.
|
83
|
+
*/
|
84
|
+
conditionMatch: function(field, test, object){
|
85
|
+
for(t in test){
|
86
|
+
switch(t){
|
87
|
+
case "==": case "eq":
|
88
|
+
if(object[field] != test[t])
|
89
|
+
return false;
|
90
|
+
break;
|
91
|
+
case "!=": case "neq":
|
92
|
+
if(object[field] == test[t])
|
93
|
+
return false;
|
94
|
+
break;
|
95
|
+
case "<": case "lt":
|
96
|
+
if(object[field] >= test[t])
|
97
|
+
return false;
|
98
|
+
break;
|
99
|
+
case "=<": case "<=": case "lte":
|
100
|
+
if(object[field] > test[t])
|
101
|
+
return false;
|
102
|
+
break;
|
103
|
+
case ">": case "gt":
|
104
|
+
if(object[field] <= test[t])
|
105
|
+
return false;
|
106
|
+
break;
|
107
|
+
case ">=": case "=>": case "gte":
|
108
|
+
if(object[field] < test[t])
|
109
|
+
return false;
|
110
|
+
break;
|
111
|
+
case "~=": case "match":
|
112
|
+
if(new RegExp(object[field],"i").test(test[t]))
|
113
|
+
return false;
|
114
|
+
break;
|
115
|
+
case "between": // Inclusive on both ends
|
116
|
+
if(object[field] < test[t][0] || object[field] > test[t][1])
|
117
|
+
return false;
|
118
|
+
break;
|
119
|
+
case "includes": // Only works with String, Array
|
120
|
+
if(object[field].indexOf(test[t]) == -1)
|
121
|
+
return false;
|
122
|
+
break;
|
123
|
+
default:
|
124
|
+
ejsLog("Invalid condition for field " + field + ": " + t + " " + test[t], "ripple-error.log");
|
125
|
+
break;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
return true;
|
129
|
+
},
|
130
|
+
/*
|
131
|
+
* Returns the mapped object without modification. Useful when
|
132
|
+
* preceded by map phases that do filtering or link phases.
|
133
|
+
*/
|
134
|
+
mapIdentity: function(value, kd, arg){
|
135
|
+
return [value];
|
136
|
+
},
|
137
|
+
/*
|
138
|
+
* Returns the passed values without modification. Useful as an
|
139
|
+
* intermediary before reduce phases that require the entire
|
140
|
+
* result set to be present (limits).
|
141
|
+
*/
|
142
|
+
reduceIdentity: function(values, arg){
|
143
|
+
return values;
|
144
|
+
}
|
145
|
+
};
|
@@ -16,7 +16,7 @@ require 'rails/generators/ripple_generator'
|
|
16
16
|
|
17
17
|
module Ripple
|
18
18
|
module Generators
|
19
|
-
class ModelGenerator <
|
19
|
+
class ModelGenerator < NamedBase
|
20
20
|
desc 'Creates a ripple model'
|
21
21
|
argument :attributes, :type => :array, :default => [], :banner => 'field:type field:type'
|
22
22
|
class_option :parent, :type => :string, :desc => "The parent class for the generated model"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'riak/test_server'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module TestServer
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Tweak this to change how your test server is configured
|
8
|
+
def test_server_config
|
9
|
+
{
|
10
|
+
:app_config => {
|
11
|
+
:riak_kv => { :js_source_dir => Ripple.config.delete(:js_source_dir) },
|
12
|
+
:riak_core => { :web_port => Ripple.config[:port] || 8098 }
|
13
|
+
},
|
14
|
+
:bin_dir => Ripple.config.delete(:bin_dir),
|
15
|
+
:temp_dir => Rails.root + "tmp/riak_test_server"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Prepares the subprocess Riak node for the test suite
|
20
|
+
def setup
|
21
|
+
unless @test_server
|
22
|
+
begin
|
23
|
+
_server = @test_server = Riak::TestServer.new(test_server_config)
|
24
|
+
@test_server.prepare!
|
25
|
+
@test_server.start
|
26
|
+
at_exit { _server.cleanup }
|
27
|
+
rescue => e
|
28
|
+
warn "Can't run tests with Riak::TestServer. Specify the location of your Riak installation in the config/ripple.yml #{Rails.env} environment."
|
29
|
+
warn e.inspect
|
30
|
+
@test_server = nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clear the data after each test run
|
36
|
+
def clear
|
37
|
+
@test_server.recycle if @test_server
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Ripple::TestServer.setup
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'rails/generators/ripple_generator'
|
15
|
+
|
16
|
+
module Ripple
|
17
|
+
module Generators
|
18
|
+
class TestGenerator < Base
|
19
|
+
desc 'Generates test helpers for Ripple. Test::Unit, RSpec and Cucumber are supported.'
|
20
|
+
# Cucumber
|
21
|
+
def create_cucumber_file
|
22
|
+
if File.directory?(Rails.root + "features/support")
|
23
|
+
template 'test_server.rb', 'features/support/ripple.rb'
|
24
|
+
insert_into_file 'features/support/ripple.rb', "\n\nAfter do\n Ripple::TestServer.clear\nend", :after => "Ripple::TestServer.setup"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# RSpec
|
29
|
+
def create_rspec_file
|
30
|
+
if File.file?(Rails.root + 'spec/spec_helper.rb')
|
31
|
+
template 'test_server.rb', 'spec/support/ripple.rb'
|
32
|
+
inject_into_file 'spec/spec_helper.rb', :after => /R[Ss]pec\.configure do \|config\|/ do
|
33
|
+
"\n config.after(:each) do\n Ripple::TestServer.clear\n end\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Test::Unit
|
39
|
+
def create_test_unit_file
|
40
|
+
if File.file?(Rails.root + 'test/test_helper.rb')
|
41
|
+
template 'test_server.rb', 'test/ripple_test_helper.rb'
|
42
|
+
inject_into_file "test/test_helper.rb", :before => "class ActiveSupport::TestCase" do
|
43
|
+
"# Setup in-memory test server for Riak\nrequire File.expand_path('../ripple_test_helper.rb', __FILE__)\n\n"
|
44
|
+
end
|
45
|
+
inject_into_class "test/test_helper.rb", ActiveSupport::TestCase do
|
46
|
+
" teardown { Ripple::TestServer.clear }\n\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -14,12 +14,26 @@
|
|
14
14
|
require "rails/generators/named_base"
|
15
15
|
require "rails/generators/active_model"
|
16
16
|
|
17
|
+
class RippleGenerator < ::Rails::Generators::Base
|
18
|
+
def create_ripple
|
19
|
+
invoke "ripple:configuration"
|
20
|
+
invoke "ripple:js"
|
21
|
+
invoke "ripple:test"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
module Ripple
|
18
26
|
# ActiveModel generators for use in a Rails project.
|
19
27
|
module Generators
|
20
28
|
# @private
|
21
|
-
class Base < ::Rails::Generators::
|
29
|
+
class Base < ::Rails::Generators::Base
|
30
|
+
def self.source_root
|
31
|
+
@_ripple_source_root ||=
|
32
|
+
File.expand_path("../#{base_name}/#{generator_name}/templates", __FILE__)
|
33
|
+
end
|
34
|
+
end
|
22
35
|
|
36
|
+
class NamedBase < ::Rails::Generators::NamedBase
|
23
37
|
def self.source_root
|
24
38
|
@_ripple_source_root ||=
|
25
39
|
File.expand_path("../#{base_name}/#{generator_name}/templates", __FILE__)
|
data/lib/ripple.rb
CHANGED
data/lib/ripple/associations.rb
CHANGED
@@ -252,7 +252,7 @@ module Ripple
|
|
252
252
|
when many?
|
253
253
|
Array === value && value.all? {|d| (embeddable? && Hash === d) || klass === d }
|
254
254
|
when one?
|
255
|
-
value.nil? || (embeddable? && Hash === value) || klass
|
255
|
+
value.nil? || (embeddable? && Hash === value) || value.kind_of?(klass)
|
256
256
|
end
|
257
257
|
end
|
258
258
|
end
|
@@ -32,6 +32,7 @@ module Ripple
|
|
32
32
|
include Write
|
33
33
|
include Query
|
34
34
|
include Dirty
|
35
|
+
include ActiveModel::MassAssignmentSecurity
|
35
36
|
end
|
36
37
|
|
37
38
|
module ClassMethods
|
@@ -64,7 +65,7 @@ module Ripple
|
|
64
65
|
# @param [Hash] attrs the attributes to assign
|
65
66
|
def attributes=(attrs)
|
66
67
|
raise ArgumentError, t('attribute_hash') unless Hash === attrs
|
67
|
-
attrs.each do |k,v|
|
68
|
+
sanitize_for_mass_assignment(attrs).each do |k,v|
|
68
69
|
next if k.to_sym == :key
|
69
70
|
if respond_to?("#{k}=")
|
70
71
|
__send__("#{k}=",v)
|
@@ -12,6 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require 'active_support/core_ext/object/blank'
|
16
|
+
require 'active_support/core_ext/object/to_json'
|
17
|
+
require 'active_support/time_with_zone'
|
18
|
+
|
15
19
|
# @private
|
16
20
|
class Object
|
17
21
|
def self.ripple_cast(value)
|
@@ -22,7 +26,7 @@ end
|
|
22
26
|
# @private
|
23
27
|
class Symbol
|
24
28
|
def self.ripple_cast(value)
|
25
|
-
return nil if value.
|
29
|
+
return nil if value.blank?
|
26
30
|
value.respond_to?(:to_s) && value.to_s.intern or raise Ripple::PropertyTypeMismatch.new(self, value)
|
27
31
|
end
|
28
32
|
end
|
@@ -30,7 +34,7 @@ end
|
|
30
34
|
# @private
|
31
35
|
class Numeric
|
32
36
|
def self.ripple_cast(value)
|
33
|
-
return nil if value.
|
37
|
+
return nil if value.blank?
|
34
38
|
raise Ripple::PropertyTypeMismatch.new(self,value) unless value.respond_to?(:to_i) && value.respond_to?(:to_f)
|
35
39
|
float_value = value.to_f
|
36
40
|
int_value = value.to_i
|
@@ -41,15 +45,15 @@ end
|
|
41
45
|
# @private
|
42
46
|
class Integer
|
43
47
|
def self.ripple_cast(value)
|
44
|
-
return nil if value.nil?
|
45
|
-
value.respond_to?(:to_i) && value.to_i or raise Ripple::PropertyTypeMismatch.new(self, value)
|
48
|
+
return nil if value.nil? || (String === value && value.blank?)
|
49
|
+
!value.is_a?(Symbol) && value.respond_to?(:to_i) && value.to_i or raise Ripple::PropertyTypeMismatch.new(self, value)
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
53
|
# @private
|
50
54
|
class Float
|
51
55
|
def self.ripple_cast(value)
|
52
|
-
return nil if value.nil?
|
56
|
+
return nil if value.nil? || (String === value && value.blank?)
|
53
57
|
value.respond_to?(:to_f) && value.to_f or raise Ripple::PropertyTypeMismatch.new(self, value)
|
54
58
|
end
|
55
59
|
end
|
@@ -97,7 +101,7 @@ class Time
|
|
97
101
|
end
|
98
102
|
|
99
103
|
def self.ripple_cast(value)
|
100
|
-
return nil if value.
|
104
|
+
return nil if value.blank?
|
101
105
|
value.respond_to?(:to_time) && value.to_time or raise Ripple::PropertyTypeMismatch.new(self, value)
|
102
106
|
end
|
103
107
|
end
|
@@ -109,7 +113,7 @@ class Date
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def self.ripple_cast(value)
|
112
|
-
return nil if value.
|
116
|
+
return nil if value.blank?
|
113
117
|
value.respond_to?(:to_date) && value.to_date or raise Ripple::PropertyTypeMismatch.new(self, value)
|
114
118
|
end
|
115
119
|
end
|
@@ -121,7 +125,17 @@ class DateTime
|
|
121
125
|
end
|
122
126
|
|
123
127
|
def self.ripple_cast(value)
|
124
|
-
return nil if value.
|
128
|
+
return nil if value.blank?
|
125
129
|
value.respond_to?(:to_datetime) && value.to_datetime or raise Ripple::PropertyTypeMismatch.new(self, value)
|
126
130
|
end
|
127
131
|
end
|
132
|
+
|
133
|
+
# @private
|
134
|
+
module ActiveSupport
|
135
|
+
class TimeWithZone
|
136
|
+
def as_json(options={})
|
137
|
+
self.utc.rfc822
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
@@ -26,7 +26,7 @@ module Ripple
|
|
26
26
|
def initialize(keys, found)
|
27
27
|
if keys.empty?
|
28
28
|
super(t("document_not_found.no_key"))
|
29
|
-
elsif keys.
|
29
|
+
elsif keys.size == 1
|
30
30
|
super(t("document_not_found.one_key", :key => keys.first))
|
31
31
|
else
|
32
32
|
missing = keys - found.compact.map(&:key)
|
@@ -57,7 +57,7 @@ module Ripple
|
|
57
57
|
def find(*args)
|
58
58
|
args.flatten!
|
59
59
|
return nil if args.empty? || args.all?(&:blank?)
|
60
|
-
return find_one(args.first) if args.
|
60
|
+
return find_one(args.first) if args.size == 1
|
61
61
|
args.map {|key| find_one(key) }
|
62
62
|
end
|
63
63
|
|
@@ -118,10 +118,9 @@ module Ripple
|
|
118
118
|
|
119
119
|
def instantiate(robject)
|
120
120
|
klass = robject.data['_type'].constantize rescue self
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
doc.key = data['key']
|
121
|
+
klass.new.tap do |doc|
|
122
|
+
doc.key = robject.key
|
123
|
+
robject.data.except("_type").each {|k,v| doc.send("#{k}=", v) } if robject.data
|
125
124
|
doc.instance_variable_set(:@new, false)
|
126
125
|
doc.instance_variable_set(:@robject, robject)
|
127
126
|
end
|
data/lib/ripple/railtie.rb
CHANGED
@@ -18,7 +18,9 @@ module Ripple
|
|
18
18
|
# during Rails initialization.
|
19
19
|
class Railtie < Rails::Railtie
|
20
20
|
initializer "ripple.configure_rails_initialization" do
|
21
|
-
|
21
|
+
if File.exist?(Rails.root + "config/ripple.yml")
|
22
|
+
Ripple.load_configuration Rails.root.join('config', 'ripple.yml'), [Rails.env]
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/ripple/timestamps.rb
CHANGED
@@ -23,7 +23,7 @@ module Ripple
|
|
23
23
|
# Adds the :created_at and :updated_at timestamp properties to
|
24
24
|
# the document.
|
25
25
|
def timestamps!
|
26
|
-
property :created_at, Time, :default => proc { Time.now
|
26
|
+
property :created_at, Time, :default => proc { Time.now }
|
27
27
|
property :updated_at, Time
|
28
28
|
before_save :touch
|
29
29
|
end
|
@@ -32,7 +32,7 @@ module Ripple
|
|
32
32
|
module InstanceMethods
|
33
33
|
# Sets the :updated_at attribute before saving the document.
|
34
34
|
def touch
|
35
|
-
self.updated_at = Time.now
|
35
|
+
self.updated_at = Time.now
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/ripple.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{ripple}
|
5
|
+
s.version = "0.8.3"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Sean Cribbs"]
|
9
|
+
s.date = %q{2010-12-13}
|
10
|
+
s.description = %q{ripple is an object-mapper library for Riak, the distributed database by Basho. It uses ActiveModel to provide an experience that integrates well with Rails 3 applications.}
|
11
|
+
s.email = %q{sean@basho.com}
|
12
|
+
s.files = ["Gemfile", "lib/rails/generators/ripple/configuration/configuration_generator.rb", "lib/rails/generators/ripple/configuration/templates/ripple.yml", "lib/rails/generators/ripple/js/js_generator.rb", "lib/rails/generators/ripple/js/templates/js/contrib.js", "lib/rails/generators/ripple/js/templates/js/ripple.js", "lib/rails/generators/ripple/model/model_generator.rb", "lib/rails/generators/ripple/model/templates/model.rb", "lib/rails/generators/ripple/test/templates/test_server.rb", "lib/rails/generators/ripple/test/test_generator.rb", "lib/rails/generators/ripple_generator.rb", "lib/ripple/associations/embedded.rb", "lib/ripple/associations/instantiators.rb", "lib/ripple/associations/linked.rb", "lib/ripple/associations/many.rb", "lib/ripple/associations/many_embedded_proxy.rb", "lib/ripple/associations/many_linked_proxy.rb", "lib/ripple/associations/one.rb", "lib/ripple/associations/one_embedded_proxy.rb", "lib/ripple/associations/one_linked_proxy.rb", "lib/ripple/associations/proxy.rb", "lib/ripple/associations.rb", "lib/ripple/attribute_methods/dirty.rb", "lib/ripple/attribute_methods/query.rb", "lib/ripple/attribute_methods/read.rb", "lib/ripple/attribute_methods/write.rb", "lib/ripple/attribute_methods.rb", "lib/ripple/callbacks.rb", "lib/ripple/conversion.rb", "lib/ripple/core_ext/casting.rb", "lib/ripple/core_ext.rb", "lib/ripple/document/bucket_access.rb", "lib/ripple/document/finders.rb", "lib/ripple/document/key.rb", "lib/ripple/document/persistence.rb", "lib/ripple/document.rb", "lib/ripple/embedded_document/finders.rb", "lib/ripple/embedded_document/persistence.rb", "lib/ripple/embedded_document.rb", "lib/ripple/i18n.rb", "lib/ripple/inspection.rb", "lib/ripple/locale/en.yml", "lib/ripple/nested_attributes.rb", "lib/ripple/properties.rb", "lib/ripple/property_type_mismatch.rb", "lib/ripple/railtie.rb", "lib/ripple/timestamps.rb", "lib/ripple/translation.rb", "lib/ripple/validations/associated_validator.rb", "lib/ripple/validations.rb", "lib/ripple.rb", "Rakefile", "ripple.gemspec", "spec/fixtures/config.yml", "spec/integration/ripple/associations_spec.rb", "spec/integration/ripple/nested_attributes_spec.rb", "spec/integration/ripple/persistence_spec.rb", "spec/ripple/associations/many_embedded_proxy_spec.rb", "spec/ripple/associations/many_linked_proxy_spec.rb", "spec/ripple/associations/one_embedded_proxy_spec.rb", "spec/ripple/associations/one_linked_proxy_spec.rb", "spec/ripple/associations/proxy_spec.rb", "spec/ripple/associations_spec.rb", "spec/ripple/attribute_methods_spec.rb", "spec/ripple/bucket_access_spec.rb", "spec/ripple/callbacks_spec.rb", "spec/ripple/conversion_spec.rb", "spec/ripple/core_ext_spec.rb", "spec/ripple/document_spec.rb", "spec/ripple/embedded_document/finders_spec.rb", "spec/ripple/embedded_document/persistence_spec.rb", "spec/ripple/embedded_document_spec.rb", "spec/ripple/finders_spec.rb", "spec/ripple/inspection_spec.rb", "spec/ripple/key_spec.rb", "spec/ripple/persistence_spec.rb", "spec/ripple/properties_spec.rb", "spec/ripple/ripple_spec.rb", "spec/ripple/timestamps_spec.rb", "spec/ripple/validations_spec.rb", "spec/spec_helper.rb", "spec/support/associations/proxies.rb", "spec/support/mocks.rb", "spec/support/models/address.rb", "spec/support/models/box.rb", "spec/support/models/car.rb", "spec/support/models/cardboard_box.rb", "spec/support/models/clock.rb", "spec/support/models/customer.rb", "spec/support/models/driver.rb", "spec/support/models/email.rb", "spec/support/models/engine.rb", "spec/support/models/family.rb", "spec/support/models/favorite.rb", "spec/support/models/invoice.rb", "spec/support/models/late_invoice.rb", "spec/support/models/note.rb", "spec/support/models/page.rb", "spec/support/models/paid_invoice.rb", "spec/support/models/passenger.rb", "spec/support/models/seat.rb", "spec/support/models/tasks.rb", "spec/support/models/tree.rb", "spec/support/models/user.rb", "spec/support/models/wheel.rb", "spec/support/models/widget.rb", "spec/support/test_server.rb", "spec/support/test_server.yml.example"]
|
13
|
+
s.homepage = %q{http://seancribbs.github.com/ripple}
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.rubygems_version = %q{1.3.7}
|
16
|
+
s.summary = %q{ripple is an object-mapper library for Riak, the distributed database by Basho.}
|
17
|
+
s.test_files = ["spec/integration/ripple/associations_spec.rb", "spec/integration/ripple/nested_attributes_spec.rb", "spec/integration/ripple/persistence_spec.rb", "spec/ripple/associations/many_embedded_proxy_spec.rb", "spec/ripple/associations/many_linked_proxy_spec.rb", "spec/ripple/associations/one_embedded_proxy_spec.rb", "spec/ripple/associations/one_linked_proxy_spec.rb", "spec/ripple/associations/proxy_spec.rb", "spec/ripple/associations_spec.rb", "spec/ripple/attribute_methods_spec.rb", "spec/ripple/bucket_access_spec.rb", "spec/ripple/callbacks_spec.rb", "spec/ripple/conversion_spec.rb", "spec/ripple/core_ext_spec.rb", "spec/ripple/document_spec.rb", "spec/ripple/embedded_document/finders_spec.rb", "spec/ripple/embedded_document/persistence_spec.rb", "spec/ripple/embedded_document_spec.rb", "spec/ripple/finders_spec.rb", "spec/ripple/inspection_spec.rb", "spec/ripple/key_spec.rb", "spec/ripple/persistence_spec.rb", "spec/ripple/properties_spec.rb", "spec/ripple/ripple_spec.rb", "spec/ripple/timestamps_spec.rb", "spec/ripple/validations_spec.rb"]
|
18
|
+
|
19
|
+
if s.respond_to? :specification_version then
|
20
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
21
|
+
s.specification_version = 3
|
22
|
+
|
23
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
24
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
|
25
|
+
s.add_runtime_dependency(%q<riak-client>, ["~> 0.8.3"])
|
26
|
+
s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.0"])
|
27
|
+
s.add_runtime_dependency(%q<activemodel>, ["~> 3.0.0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
30
|
+
s.add_dependency(%q<riak-client>, ["~> 0.8.3"])
|
31
|
+
s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
|
32
|
+
s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
36
|
+
s.add_dependency(%q<riak-client>, ["~> 0.8.3"])
|
37
|
+
s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
|
38
|
+
s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
|
39
|
+
end
|
40
|
+
end
|
@@ -15,7 +15,8 @@ require File.expand_path("../../../spec_helper", __FILE__)
|
|
15
15
|
|
16
16
|
describe Ripple::Associations::OneLinkedProxy do
|
17
17
|
require 'support/models/tasks'
|
18
|
-
|
18
|
+
require 'support/models/family'
|
19
|
+
|
19
20
|
before :each do
|
20
21
|
@person = Person.new {|p| p.key = "riak-user" }
|
21
22
|
@profile = Profile.new {|t| t.key = "one" }
|
@@ -28,7 +29,7 @@ describe Ripple::Associations::OneLinkedProxy do
|
|
28
29
|
it "should be blank before the associated document is set" do
|
29
30
|
@person.profile.should_not be_present
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
it "should accept a single document" do
|
33
34
|
lambda { @person.profile = @profile }.should_not raise_error
|
34
35
|
end
|
@@ -48,8 +49,8 @@ describe Ripple::Associations::OneLinkedProxy do
|
|
48
49
|
@profile.should_receive(:save).and_return(true)
|
49
50
|
@person.profile = @profile
|
50
51
|
end
|
51
|
-
|
52
|
-
it "should link-walk to the associated document when accessing" do
|
52
|
+
|
53
|
+
it "should link-walk to the associated document when accessing" do
|
53
54
|
@person.robject.links << @profile.robject.to_link("profile")
|
54
55
|
@person.robject.should_receive(:walk).with(Riak::WalkSpec.new(:bucket => "profiles", :tag => "profile")).and_return([[@profile.robject]])
|
55
56
|
@person.profile.should be_present
|
@@ -59,13 +60,28 @@ describe Ripple::Associations::OneLinkedProxy do
|
|
59
60
|
@person.robject.links.should be_empty
|
60
61
|
@person.profile.should be_nil
|
61
62
|
end
|
62
|
-
|
63
|
+
|
63
64
|
it "should replace associated document with a new one" do
|
64
65
|
@person.profile = @profile
|
65
66
|
@person.profile = @other_profile
|
66
67
|
@person.profile.should == @other_profile
|
67
68
|
end
|
68
69
|
|
70
|
+
it "replaces the associated document with the target of the proxy" do
|
71
|
+
@other_person = Person.new {|p| p.key = "another-riak-user" }
|
72
|
+
@other_person.profile = @other_profile
|
73
|
+
|
74
|
+
@person.profile = @other_person.profile
|
75
|
+
@person.profile.should == @other_profile
|
76
|
+
end
|
77
|
+
|
78
|
+
it "refuses assigning a proxy if its target is the wrong type" do
|
79
|
+
parent = Parent.new
|
80
|
+
parent.child = Child.new
|
81
|
+
|
82
|
+
lambda { @person.profile = parent.child }.should raise_error
|
83
|
+
end
|
84
|
+
|
69
85
|
# it "should be able to build a new associated document" do
|
70
86
|
# @person.profile.build
|
71
87
|
# end
|
@@ -130,6 +130,13 @@ describe Ripple::AttributeMethods do
|
|
130
130
|
@widget.changes.should == {"name" => ["widget", "foobar"]}
|
131
131
|
end
|
132
132
|
|
133
|
+
it "should report that an attribute is changed only if its value actually changes" do
|
134
|
+
@widget.name = "widget"
|
135
|
+
@widget.changed?.should be_false
|
136
|
+
@widget.name_changed?.should be_false
|
137
|
+
@widget.changes.should be_blank
|
138
|
+
end
|
139
|
+
|
133
140
|
it "should refresh the attribute methods when adding a new property" do
|
134
141
|
Widget.should_receive(:undefine_attribute_methods)
|
135
142
|
Widget.property :start_date, Date
|
@@ -137,7 +144,7 @@ describe Ripple::AttributeMethods do
|
|
137
144
|
end
|
138
145
|
|
139
146
|
it "should provide a hash representation of all of the attributes" do
|
140
|
-
@widget.attributes.should == {"name" => "widget", "size" => nil, "manufactured" => false}
|
147
|
+
@widget.attributes.should == {"name" => "widget", "size" => nil, "manufactured" => false, "shipped_at" => nil}
|
141
148
|
end
|
142
149
|
|
143
150
|
it "should load attributes from mass assignment" do
|
@@ -177,4 +184,9 @@ describe Ripple::AttributeMethods do
|
|
177
184
|
@widget = Widget.new
|
178
185
|
lambda { @widget.attributes = nil }.should raise_error(ArgumentError)
|
179
186
|
end
|
187
|
+
|
188
|
+
it "should protect attributes from mass assignment" do
|
189
|
+
@widget = Widget.new(:manufactured => true)
|
190
|
+
@widget.manufactured.should be_false
|
191
|
+
end
|
180
192
|
end
|
@@ -35,6 +35,14 @@ describe DateTime do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
describe ActiveSupport::TimeWithZone do
|
39
|
+
it "serializes to JSON in UTC, RFC 822 format" do
|
40
|
+
time = Time.utc(2010,3,16,12)
|
41
|
+
zone = ActiveSupport::TimeZone['Alaska']
|
42
|
+
ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
describe "Boolean" do
|
39
47
|
it "should be available to properties on documents" do
|
40
48
|
lambda {
|
data/spec/ripple/finders_spec.rb
CHANGED
@@ -71,6 +71,11 @@ describe Ripple::Document::Finders do
|
|
71
71
|
lambda { Box.find!("square") }.should_not raise_error(Ripple::DocumentNotFound)
|
72
72
|
end
|
73
73
|
|
74
|
+
it "should raise an exception when finding an existing document that has properties we don't know about" do
|
75
|
+
@http.should_receive(:get).with(200, "/riak/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"non_existent_property":"whatever"}'})
|
76
|
+
lambda { Box.find("square") }.should raise_error
|
77
|
+
end
|
78
|
+
|
74
79
|
it "should return the document when calling find!" do
|
75
80
|
@http.should_receive(:get).with(200, "/riak/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
76
81
|
box = Box.find!("square")
|
@@ -54,10 +54,11 @@ describe Ripple::Document::Persistence do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should instantiate and save a new object to riak" do
|
57
|
-
json = @widget.attributes.merge(:size => 10, :_type => 'Widget').to_json
|
57
|
+
json = @widget.attributes.merge(:size => 10, :shipped_at => "Sat, 01 Jan 2000 20:15:01 -0000", :_type => 'Widget').to_json
|
58
58
|
@http.should_receive(:post).with(201, "/riak/", "widgets", an_instance_of(Hash), json, hash_including("Content-Type" => "application/json")).and_return(:code => 201, :headers => {'location' => ["/riak/widgets/new_widget"]})
|
59
|
-
@widget = Widget.create(:size => 10)
|
59
|
+
@widget = Widget.create(:size => 10, :shipped_at => Time.utc(2000,"jan",1,20,15,1))
|
60
60
|
@widget.size.should == 10
|
61
|
+
@widget.shipped_at.should == Time.utc(2000,"jan",1,20,15,1)
|
61
62
|
@widget.should_not be_a_new_record
|
62
63
|
end
|
63
64
|
|
@@ -72,14 +73,15 @@ describe Ripple::Document::Persistence do
|
|
72
73
|
end
|
73
74
|
|
74
75
|
it "should reload a saved object" do
|
75
|
-
json = @widget.attributes.merge(
|
76
|
+
json = @widget.attributes.merge(:_type => "Widget").to_json
|
76
77
|
@http.should_receive(:post).with(201, "/riak/", "widgets", an_instance_of(Hash), json, hash_including("Content-Type" => "application/json")).and_return(:code => 201, :headers => {'location' => ["/riak/widgets/new_widget"]})
|
77
78
|
@widget.save
|
78
|
-
@http.should_receive(:get).and_return(:code => 200, :headers => {'content-type' => ["application/json"]}, :body => '{"name":"spring","size":10}')
|
79
|
+
@http.should_receive(:get).and_return(:code => 200, :headers => {'content-type' => ["application/json"]}, :body => '{"name":"spring","size":10,"shipped_at":"Sat, 01 Jan 2000 20:15:01 -0000","_type":"Widget"}')
|
79
80
|
@widget.reload
|
80
81
|
@widget.changes.should be_blank
|
81
82
|
@widget.name.should == "spring"
|
82
83
|
@widget.size.should == 10
|
84
|
+
@widget.shipped_at.should == Time.utc(2000,"jan",1,20,15,1)
|
83
85
|
end
|
84
86
|
|
85
87
|
it "should destroy a saved object" do
|
@@ -145,13 +145,18 @@ describe Ripple::Property do
|
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
|
-
[0.0, "0", " 000"
|
148
|
+
[0.0, "0", " 000"].each do |v|
|
149
149
|
it "should cast #{v.inspect} to 0" do
|
150
150
|
@prop.type_cast(v).should == 0
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
|
154
|
+
it "should not cast the blank string" do
|
155
|
+
@prop.type_cast("").should be_nil
|
156
|
+
@prop.type_cast(" ").should be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
[true, false, [], {}, :symbol, ["something else"]].each do |v|
|
155
160
|
it "should raise an error casting #{v.inspect}" do
|
156
161
|
lambda { @prop.type_cast(v) }.should raise_error(Ripple::PropertyTypeMismatch)
|
157
162
|
end
|
@@ -163,7 +168,7 @@ describe Ripple::Property do
|
|
163
168
|
@prop = Ripple::Property.new(:foo, Float)
|
164
169
|
end
|
165
170
|
|
166
|
-
[0, "0", "0.0", " 0.0"
|
171
|
+
[0, "0", "0.0", " 0.0"].each do |v|
|
167
172
|
it "should cast #{v.inspect} to 0.0" do
|
168
173
|
@prop.type_cast(v).should == 0.0
|
169
174
|
end
|
@@ -175,6 +180,11 @@ describe Ripple::Property do
|
|
175
180
|
end
|
176
181
|
end
|
177
182
|
|
183
|
+
it "should not cast the blank string" do
|
184
|
+
@prop.type_cast("").should be_nil
|
185
|
+
@prop.type_cast(" ").should be_nil
|
186
|
+
end
|
187
|
+
|
178
188
|
[true, false, :symbol, [], {}].each do |v|
|
179
189
|
it "should raise an error casting #{v.inspect}" do
|
180
190
|
lambda { @prop.type_cast(v) }.should raise_error(Ripple::PropertyTypeMismatch)
|
@@ -198,6 +208,11 @@ describe Ripple::Property do
|
|
198
208
|
@prop.type_cast(v).should be_kind_of(Float)
|
199
209
|
end
|
200
210
|
end
|
211
|
+
|
212
|
+
it "should not cast the blank string" do
|
213
|
+
@prop.type_cast("").should be_nil
|
214
|
+
@prop.type_cast(" ").should be_nil
|
215
|
+
end
|
201
216
|
end
|
202
217
|
|
203
218
|
describe "when type is a Time type" do
|
@@ -210,6 +225,13 @@ describe Ripple::Property do
|
|
210
225
|
@prop.type_cast(v).should == Time.utc(2010,03,16,12)
|
211
226
|
end
|
212
227
|
end
|
228
|
+
|
229
|
+
it "should not cast blank types" do
|
230
|
+
@prop.type_cast([]).should be_nil
|
231
|
+
@prop.type_cast({}).should be_nil
|
232
|
+
@prop.type_cast("").should be_nil
|
233
|
+
@prop.type_cast(" ").should be_nil
|
234
|
+
end
|
213
235
|
end
|
214
236
|
|
215
237
|
describe "when type is a Date type" do
|
@@ -222,6 +244,13 @@ describe Ripple::Property do
|
|
222
244
|
@prop.type_cast(v).should == Date.civil(2010,3,16)
|
223
245
|
end
|
224
246
|
end
|
247
|
+
|
248
|
+
it "should not cast blank types" do
|
249
|
+
@prop.type_cast([]).should be_nil
|
250
|
+
@prop.type_cast({}).should be_nil
|
251
|
+
@prop.type_cast("").should be_nil
|
252
|
+
@prop.type_cast(" ").should be_nil
|
253
|
+
end
|
225
254
|
end
|
226
255
|
end
|
227
256
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 8
|
8
|
-
-
|
9
|
-
version: 0.8.
|
8
|
+
- 3
|
9
|
+
version: 0.8.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Sean Cribbs
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-12-13 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -43,8 +43,8 @@ dependencies:
|
|
43
43
|
segments:
|
44
44
|
- 0
|
45
45
|
- 8
|
46
|
-
-
|
47
|
-
version: 0.8.
|
46
|
+
- 3
|
47
|
+
version: 0.8.3
|
48
48
|
type: :runtime
|
49
49
|
version_requirements: *id002
|
50
50
|
- !ruby/object:Gem::Dependency
|
@@ -78,7 +78,7 @@ dependencies:
|
|
78
78
|
type: :runtime
|
79
79
|
version_requirements: *id004
|
80
80
|
description: ripple is an object-mapper library for Riak, the distributed database by Basho. It uses ActiveModel to provide an experience that integrates well with Rails 3 applications.
|
81
|
-
email:
|
81
|
+
email: sean@basho.com
|
82
82
|
executables: []
|
83
83
|
|
84
84
|
extensions: []
|
@@ -86,8 +86,16 @@ extensions: []
|
|
86
86
|
extra_rdoc_files: []
|
87
87
|
|
88
88
|
files:
|
89
|
+
- Gemfile
|
90
|
+
- lib/rails/generators/ripple/configuration/configuration_generator.rb
|
91
|
+
- lib/rails/generators/ripple/configuration/templates/ripple.yml
|
92
|
+
- lib/rails/generators/ripple/js/js_generator.rb
|
93
|
+
- lib/rails/generators/ripple/js/templates/js/contrib.js
|
94
|
+
- lib/rails/generators/ripple/js/templates/js/ripple.js
|
89
95
|
- lib/rails/generators/ripple/model/model_generator.rb
|
90
96
|
- lib/rails/generators/ripple/model/templates/model.rb
|
97
|
+
- lib/rails/generators/ripple/test/templates/test_server.rb
|
98
|
+
- lib/rails/generators/ripple/test/test_generator.rb
|
91
99
|
- lib/rails/generators/ripple_generator.rb
|
92
100
|
- lib/ripple/associations/embedded.rb
|
93
101
|
- lib/ripple/associations/instantiators.rb
|
@@ -130,6 +138,7 @@ files:
|
|
130
138
|
- lib/ripple/validations.rb
|
131
139
|
- lib/ripple.rb
|
132
140
|
- Rakefile
|
141
|
+
- ripple.gemspec
|
133
142
|
- spec/fixtures/config.yml
|
134
143
|
- spec/integration/ripple/associations_spec.rb
|
135
144
|
- spec/integration/ripple/nested_attributes_spec.rb
|
@@ -184,6 +193,7 @@ files:
|
|
184
193
|
- spec/support/models/wheel.rb
|
185
194
|
- spec/support/models/widget.rb
|
186
195
|
- spec/support/test_server.rb
|
196
|
+
- spec/support/test_server.yml.example
|
187
197
|
has_rdoc: true
|
188
198
|
homepage: http://seancribbs.github.com/ripple
|
189
199
|
licenses: []
|
@@ -243,30 +253,3 @@ test_files:
|
|
243
253
|
- spec/ripple/ripple_spec.rb
|
244
254
|
- spec/ripple/timestamps_spec.rb
|
245
255
|
- spec/ripple/validations_spec.rb
|
246
|
-
- spec/spec_helper.rb
|
247
|
-
- spec/support/associations/proxies.rb
|
248
|
-
- spec/support/mocks.rb
|
249
|
-
- spec/support/models/address.rb
|
250
|
-
- spec/support/models/box.rb
|
251
|
-
- spec/support/models/car.rb
|
252
|
-
- spec/support/models/cardboard_box.rb
|
253
|
-
- spec/support/models/clock.rb
|
254
|
-
- spec/support/models/customer.rb
|
255
|
-
- spec/support/models/driver.rb
|
256
|
-
- spec/support/models/email.rb
|
257
|
-
- spec/support/models/engine.rb
|
258
|
-
- spec/support/models/family.rb
|
259
|
-
- spec/support/models/favorite.rb
|
260
|
-
- spec/support/models/invoice.rb
|
261
|
-
- spec/support/models/late_invoice.rb
|
262
|
-
- spec/support/models/note.rb
|
263
|
-
- spec/support/models/page.rb
|
264
|
-
- spec/support/models/paid_invoice.rb
|
265
|
-
- spec/support/models/passenger.rb
|
266
|
-
- spec/support/models/seat.rb
|
267
|
-
- spec/support/models/tasks.rb
|
268
|
-
- spec/support/models/tree.rb
|
269
|
-
- spec/support/models/user.rb
|
270
|
-
- spec/support/models/wheel.rb
|
271
|
-
- spec/support/models/widget.rb
|
272
|
-
- spec/support/test_server.rb
|