better-ripple 1.0.0

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 (77) hide show
  1. data/LICENSE +17 -0
  2. data/README.md +182 -0
  3. data/RELEASE_NOTES.md +284 -0
  4. data/better-ripple.gemspec +55 -0
  5. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
  6. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +25 -0
  7. data/lib/rails/generators/ripple/js/js_generator.rb +13 -0
  8. data/lib/rails/generators/ripple/js/templates/js/contrib.js +63 -0
  9. data/lib/rails/generators/ripple/js/templates/js/iso8601.js +76 -0
  10. data/lib/rails/generators/ripple/js/templates/js/ripple.js +132 -0
  11. data/lib/rails/generators/ripple/model/model_generator.rb +20 -0
  12. data/lib/rails/generators/ripple/model/templates/model.rb.erb +10 -0
  13. data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
  14. data/lib/rails/generators/ripple/observer/templates/observer.rb.erb +2 -0
  15. data/lib/rails/generators/ripple/test/templates/cucumber.rb.erb +7 -0
  16. data/lib/rails/generators/ripple/test/test_generator.rb +44 -0
  17. data/lib/rails/generators/ripple_generator.rb +79 -0
  18. data/lib/ripple.rb +86 -0
  19. data/lib/ripple/associations.rb +380 -0
  20. data/lib/ripple/associations/embedded.rb +35 -0
  21. data/lib/ripple/associations/instantiators.rb +26 -0
  22. data/lib/ripple/associations/linked.rb +65 -0
  23. data/lib/ripple/associations/many.rb +38 -0
  24. data/lib/ripple/associations/many_embedded_proxy.rb +39 -0
  25. data/lib/ripple/associations/many_linked_proxy.rb +66 -0
  26. data/lib/ripple/associations/many_reference_proxy.rb +95 -0
  27. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  28. data/lib/ripple/associations/one.rb +20 -0
  29. data/lib/ripple/associations/one_embedded_proxy.rb +35 -0
  30. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  31. data/lib/ripple/associations/one_linked_proxy.rb +26 -0
  32. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  33. data/lib/ripple/associations/proxy.rb +118 -0
  34. data/lib/ripple/attribute_methods.rb +132 -0
  35. data/lib/ripple/attribute_methods/dirty.rb +59 -0
  36. data/lib/ripple/attribute_methods/query.rb +34 -0
  37. data/lib/ripple/attribute_methods/read.rb +28 -0
  38. data/lib/ripple/attribute_methods/write.rb +25 -0
  39. data/lib/ripple/callbacks.rb +71 -0
  40. data/lib/ripple/conflict/basic_resolver.rb +86 -0
  41. data/lib/ripple/conflict/document_hooks.rb +46 -0
  42. data/lib/ripple/conflict/resolver.rb +79 -0
  43. data/lib/ripple/conflict/test_helper.rb +34 -0
  44. data/lib/ripple/conversion.rb +29 -0
  45. data/lib/ripple/core_ext.rb +3 -0
  46. data/lib/ripple/core_ext/casting.rb +151 -0
  47. data/lib/ripple/core_ext/indexes.rb +89 -0
  48. data/lib/ripple/core_ext/object.rb +8 -0
  49. data/lib/ripple/document.rb +105 -0
  50. data/lib/ripple/document/bucket_access.rb +25 -0
  51. data/lib/ripple/document/finders.rb +131 -0
  52. data/lib/ripple/document/key.rb +35 -0
  53. data/lib/ripple/document/link.rb +30 -0
  54. data/lib/ripple/document/persistence.rb +130 -0
  55. data/lib/ripple/embedded_document.rb +63 -0
  56. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  57. data/lib/ripple/embedded_document/finders.rb +26 -0
  58. data/lib/ripple/embedded_document/persistence.rb +75 -0
  59. data/lib/ripple/i18n.rb +5 -0
  60. data/lib/ripple/indexes.rb +151 -0
  61. data/lib/ripple/inspection.rb +32 -0
  62. data/lib/ripple/locale/en.yml +26 -0
  63. data/lib/ripple/locale/fr.yml +24 -0
  64. data/lib/ripple/nested_attributes.rb +275 -0
  65. data/lib/ripple/observable.rb +28 -0
  66. data/lib/ripple/properties.rb +74 -0
  67. data/lib/ripple/property_type_mismatch.rb +12 -0
  68. data/lib/ripple/railtie.rb +26 -0
  69. data/lib/ripple/railties/ripple.rake +103 -0
  70. data/lib/ripple/serialization.rb +82 -0
  71. data/lib/ripple/test_server.rb +35 -0
  72. data/lib/ripple/timestamps.rb +25 -0
  73. data/lib/ripple/translation.rb +18 -0
  74. data/lib/ripple/validations.rb +65 -0
  75. data/lib/ripple/validations/associated_validator.rb +43 -0
  76. data/lib/ripple/version.rb +3 -0
  77. metadata +310 -0
@@ -0,0 +1,55 @@
1
+ # This file is auto-generated!
2
+ # DO NOT EDIT THIS FILE DIRECTLY!
3
+ # Instead, edit the Rakefile and run 'rake gemspec:generate'.# -*- encoding: utf-8 -*-
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "better-ripple"
7
+ s.version = "1.0.0"
8
+
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.authors = ["Jon Frisby", "Sean Cribbs"]
11
+ s.date = "2012-10-10"
12
+ s.description = "better-ripple is an improved version of ripple, an object-mapper library for Riak. It uses ActiveModel to provide an experience that integrates well with Rails 3 applications."
13
+ s.email = ["jon@cloudability.com", "sean@basho.com"]
14
+ s.files = ["LICENSE", "README.md", "RELEASE_NOTES.md", "better-ripple.gemspec", "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/iso8601.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.erb", "lib/rails/generators/ripple/observer/observer_generator.rb", "lib/rails/generators/ripple/observer/templates/observer.rb.erb", "lib/rails/generators/ripple/test/templates/cucumber.rb.erb", "lib/rails/generators/ripple/test/test_generator.rb", "lib/rails/generators/ripple_generator.rb", "lib/ripple.rb", "lib/ripple/associations.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/many_reference_proxy.rb", "lib/ripple/associations/many_stored_key_proxy.rb", "lib/ripple/associations/one.rb", "lib/ripple/associations/one_embedded_proxy.rb", "lib/ripple/associations/one_key_proxy.rb", "lib/ripple/associations/one_linked_proxy.rb", "lib/ripple/associations/one_stored_key_proxy.rb", "lib/ripple/associations/proxy.rb", "lib/ripple/attribute_methods.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/callbacks.rb", "lib/ripple/conflict/basic_resolver.rb", "lib/ripple/conflict/document_hooks.rb", "lib/ripple/conflict/resolver.rb", "lib/ripple/conflict/test_helper.rb", "lib/ripple/conversion.rb", "lib/ripple/core_ext.rb", "lib/ripple/core_ext/casting.rb", "lib/ripple/core_ext/indexes.rb", "lib/ripple/core_ext/object.rb", "lib/ripple/document.rb", "lib/ripple/document/bucket_access.rb", "lib/ripple/document/finders.rb", "lib/ripple/document/key.rb", "lib/ripple/document/link.rb", "lib/ripple/document/persistence.rb", "lib/ripple/embedded_document.rb", "lib/ripple/embedded_document/around_callbacks.rb", "lib/ripple/embedded_document/finders.rb", "lib/ripple/embedded_document/persistence.rb", "lib/ripple/i18n.rb", "lib/ripple/indexes.rb", "lib/ripple/inspection.rb", "lib/ripple/locale/en.yml", "lib/ripple/locale/fr.yml", "lib/ripple/nested_attributes.rb", "lib/ripple/observable.rb", "lib/ripple/properties.rb", "lib/ripple/property_type_mismatch.rb", "lib/ripple/railtie.rb", "lib/ripple/railties/ripple.rake", "lib/ripple/serialization.rb", "lib/ripple/test_server.rb", "lib/ripple/timestamps.rb", "lib/ripple/translation.rb", "lib/ripple/validations.rb", "lib/ripple/validations/associated_validator.rb", "lib/ripple/version.rb"]
15
+ s.homepage = "http://github.com/cloudability/better-ripple"
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = "1.8.24"
18
+ s.summary = "better-ripple is an improved version of ripple, an object-mapper library for Riak."
19
+
20
+ if s.respond_to? :specification_version then
21
+ s.specification_version = 3
22
+
23
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
24
+ s.add_runtime_dependency(%q<better-riak-client>, ["~> 1.0.0"])
25
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
26
+ s.add_development_dependency(%q<activesupport>, [">= 3.0.0"])
27
+ s.add_runtime_dependency(%q<activemodel>, [">= 3.0.0"])
28
+ s.add_development_dependency(%q<activemodel>, [">= 3.0.0"])
29
+ s.add_runtime_dependency(%q<tzinfo>, [">= 0"])
30
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
31
+ s.add_development_dependency(%q<rake>, [">= 0"])
32
+ s.add_development_dependency(%q<ammeter>, ["~> 0.2.2"])
33
+ else
34
+ s.add_dependency(%q<better-riak-client>, ["~> 1.0.0"])
35
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
36
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
37
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
38
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
39
+ s.add_dependency(%q<tzinfo>, [">= 0"])
40
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
41
+ s.add_dependency(%q<rake>, [">= 0"])
42
+ s.add_dependency(%q<ammeter>, ["~> 0.2.2"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<better-riak-client>, ["~> 1.0.0"])
46
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
47
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
48
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
49
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
50
+ s.add_dependency(%q<tzinfo>, [">= 0"])
51
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
52
+ s.add_dependency(%q<rake>, [">= 0"])
53
+ s.add_dependency(%q<ammeter>, ["~> 0.2.2"])
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators/ripple_generator'
2
+
3
+ module Ripple
4
+ module Generators
5
+ class ConfigurationGenerator < Base
6
+ desc 'Generates a configuration file for Ripple.'
7
+
8
+ def create_configuration_file
9
+ template 'ripple.yml', 'config/ripple.yml'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ # Configure Riak connections for the Ripple library.
2
+ development:
3
+ http_port: 8098
4
+ pb_port: 8087
5
+ host: 127.0.0.1
6
+ source: /usr/local/bin #Default for Homebrew.
7
+
8
+ # The test environment has additional keys for configuring the
9
+ # Riak::TestServer for your test/spec suite:
10
+ #
11
+ # * bin_dir specifies the path to the "riak" script that you use to
12
+ # start Riak (just the directory)
13
+ # * js_source_dir specifies where your custom Javascript functions for
14
+ # MapReduce should be loaded from. Usually app/mapreduce.
15
+ test:
16
+ http_port: 9000
17
+ pb_port: 9002
18
+ host: 127.0.0.1
19
+ source: /usr/local/bin # Default for Homebrew.
20
+ js_source_dir: <%%= Rails.root + "app/mapreduce" %>
21
+
22
+ production:
23
+ http_port: 8098
24
+ pb_port: 8087
25
+ host: 127.0.0.1
@@ -0,0 +1,13 @@
1
+ require 'rails/generators/ripple_generator'
2
+
3
+ module Ripple
4
+ module Generators
5
+ class JsGenerator < Base
6
+ desc 'Generates Javascript built-ins for use in your queries.'
7
+
8
+ def create_js_files
9
+ directory 'js', 'app/mapreduce'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ // -------------------------------------------------------------------
2
+ //
3
+ // This file contains Javascript MapReduce functions copied from the
4
+ // "Riak Function Contrib" project.
5
+ //
6
+ Riak.Contrib = {
7
+ // Count keys in a group of results.
8
+ // http://contrib.basho.com/count_keys.html
9
+ mapCount: function(){
10
+ return [1];
11
+ },
12
+
13
+ // Generate commonly used statistics from an array of numbers.
14
+ // Supports count, sum, min, max, percentiles, mean, variance, and
15
+ // stddev.
16
+ // http://contrib.basho.com/stats.html
17
+ reduceStats: function(data) {
18
+ var result = {};
19
+
20
+ data.sort(function(a,b){return a-b;});
21
+ result.count = data.length;
22
+
23
+ // Since the data is sorted, the minimum value
24
+ // is at the beginning of the array, the median
25
+ // value is in the middle of the array, and the
26
+ // maximum value is at the end of the array.
27
+ result.min = data[0];
28
+ result.max = data[data.length - 1];
29
+
30
+ var ntileFunc = function(percentile){
31
+ if (data.length == 1) return data[0];
32
+ var ntileRank = ((percentile/100) * (data.length - 1)) + 1;
33
+ var integralRank = Math.floor(ntileRank);
34
+ var fractionalRank = ntileRank - integralRank;
35
+ var lowerValue = data[integralRank-1];
36
+ var upperValue = data[integralRank];
37
+ return (fractionalRank * (upperValue - lowerValue)) + lowerValue;
38
+ };
39
+
40
+ result.percentile25 = ntileFunc(25);
41
+ result.median = ntileFunc(50);
42
+ result.percentile75 = ntileFunc(75);
43
+ result.percentile99 = ntileFunc(99);
44
+
45
+ // Compute the mean and variance using a
46
+ // numerically stable algorithm.
47
+ var sqsum = 0;
48
+ result.mean = data[0];
49
+ result.sum = result.mean * result.count;
50
+ for (var i = 1; i < data.length; ++i) {
51
+ var x = data[i];
52
+ var delta = x - result.mean;
53
+ var sweep = i + 1.0;
54
+ result.mean += delta / sweep;
55
+ sqsum += delta * delta * (i / sweep);
56
+ result.sum += x;
57
+ }
58
+ result.variance = sqsum / result.count;
59
+ result.sdev = Math.sqrt(result.variance);
60
+
61
+ return result;
62
+ }
63
+ };
@@ -0,0 +1,76 @@
1
+ // Written by Paul Sowden, 2005
2
+ // http://delete.me.uk/2005/03/iso8601.html
3
+ // Released under the Academic Free License
4
+
5
+ Date.prototype.setISO8601 = function (string) {
6
+ var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
7
+ "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
8
+ "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
9
+ var d = string.match(new RegExp(regexp));
10
+
11
+ var offset = 0;
12
+ var date = new Date(d[1], 0, 1);
13
+
14
+ if (d[3]) { date.setMonth(d[3] - 1); }
15
+ if (d[5]) { date.setDate(d[5]); }
16
+ if (d[7]) { date.setHours(d[7]); }
17
+ if (d[8]) { date.setMinutes(d[8]); }
18
+ if (d[10]) { date.setSeconds(d[10]); }
19
+ if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
20
+ if (d[14]) {
21
+ offset = (Number(d[16]) * 60) + Number(d[17]);
22
+ offset *= ((d[15] == '-') ? 1 : -1);
23
+ }
24
+
25
+ offset -= date.getTimezoneOffset();
26
+ time = (Number(date) + (offset * 60 * 1000));
27
+ this.setTime(Number(time));
28
+ }
29
+
30
+ Date.prototype.iso8601 = function (format, offset) {
31
+ /* accepted values for the format [1-6]:
32
+ 1 Year:
33
+ YYYY (eg 1997)
34
+ 2 Year and month:
35
+ YYYY-MM (eg 1997-07)
36
+ 3 Complete date:
37
+ YYYY-MM-DD (eg 1997-07-16)
38
+ 4 Complete date plus hours and minutes:
39
+ YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
40
+ 5 Complete date plus hours, minutes and seconds:
41
+ YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
42
+ 6 Complete date plus hours, minutes, seconds and a decimal
43
+ fraction of a second
44
+ YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
45
+ */
46
+ if (!format) { var format = 6; }
47
+ if (!offset) {
48
+ var offset = 'Z';
49
+ var date = this;
50
+ } else {
51
+ var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
52
+ var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
53
+ offsetnum *= ((d[1] == '-') ? -1 : 1);
54
+ var date = new Date(Number(Number(this) + (offsetnum * 60000)));
55
+ }
56
+
57
+ var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }
58
+
59
+ var str = "";
60
+ str += date.getUTCFullYear();
61
+ if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
62
+ if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
63
+ if (format > 3) {
64
+ str += "T" + zeropad(date.getUTCHours()) +
65
+ ":" + zeropad(date.getUTCMinutes());
66
+ }
67
+ if (format > 5) {
68
+ var secs = Number(date.getUTCSeconds() + "." +
69
+ ((date.getUTCMilliseconds() < 100) ? '0' : '') +
70
+ zeropad(date.getUTCMilliseconds()));
71
+ str += ":" + zeropad(secs);
72
+ } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }
73
+
74
+ if (format > 3) { str += offset; }
75
+ return str;
76
+ }
@@ -0,0 +1,132 @@
1
+
2
+ /*
3
+ * Namespace for Ripple's built-in MapReduce functions.
4
+ */
5
+ var Ripple = {
6
+ /*
7
+ * Filter input values by simple equality test on passed "fields"
8
+ * argument. Returns bucket/key pairs for use in later map phases.
9
+ *
10
+ * Raw Phase Example:
11
+ * {"map":{
12
+ * "language":"javascript",
13
+ * "name":"Ripple.filterByFields",
14
+ * "arg":{"manufactured":true, "name":"widget"}
15
+ * }}
16
+ *
17
+ * Ruby invocation example:
18
+ * mr.map("Ripple.filterByFields",
19
+ * :arg => {:manufactured => true, :name => "widget"})
20
+ *
21
+ */
22
+ filterByFields: function(value, keyData, fields){
23
+ var object = Riak.mapValuesJson(value)[0];
24
+ for(field in fields){
25
+ if(object[field] != fields[field])
26
+ return [];
27
+ }
28
+ return [[value.bucket, value.key]];
29
+ },
30
+ /*
31
+ * Filter input values by various conditions passed as the
32
+ * "conditions" argument. Returns bucket/key pairs for use in
33
+ * later map phases.
34
+ *
35
+ * Valid operators:
36
+ * ==, eq (equality)
37
+ * !=, neq (inequality)
38
+ * <, lt (less than)
39
+ * =<, <=, lte (less than or equal)
40
+ * >, gt (greater than)
41
+ * >=, =>, gte (greater than or equal)
42
+ * ~=, match (regular expression match)
43
+ * between (inclusive numeric range)
44
+ * includes (String or Array inclusion)
45
+ *
46
+ * Example:
47
+ * {"map":{
48
+ * "language":"javascript",
49
+ * "name":"Ripple.filterByConditions",
50
+ * "arg":{"tags":{"includes":"riak"}, "title":{"~=":"schema"}}
51
+ * }}
52
+ *
53
+ * Ruby invocation example:
54
+ * mr.map("Ripple.filterByConditions",
55
+ * :arg => {:tags => {:includes => "riak"},
56
+ * :title => {"~=" => "schema"}})
57
+ */
58
+ filterByConditions: function(value, keyData, conditions){
59
+ var object = Riak.mapValuesJson(value)[0];
60
+ for(condition in conditions){
61
+ if(!Ripple.conditionMatch(condition, conditions[condition], object))
62
+ return [];
63
+ }
64
+ return [[value.bucket, value.key]];
65
+ },
66
+ /*
67
+ * Given a specific field and test, returns whether the object
68
+ * matches the condition specified by the test. Used internally by
69
+ * Ripple.filterByConditions map phases.
70
+ */
71
+ conditionMatch: function(field, test, object){
72
+ for(t in test){
73
+ switch(t){
74
+ case "==": case "eq":
75
+ if(object[field] != test[t])
76
+ return false;
77
+ break;
78
+ case "!=": case "neq":
79
+ if(object[field] == test[t])
80
+ return false;
81
+ break;
82
+ case "<": case "lt":
83
+ if(object[field] >= test[t])
84
+ return false;
85
+ break;
86
+ case "=<": case "<=": case "lte":
87
+ if(object[field] > test[t])
88
+ return false;
89
+ break;
90
+ case ">": case "gt":
91
+ if(object[field] <= test[t])
92
+ return false;
93
+ break;
94
+ case ">=": case "=>": case "gte":
95
+ if(object[field] < test[t])
96
+ return false;
97
+ break;
98
+ case "~=": case "match":
99
+ if(new RegExp(object[field],"i").test(test[t]))
100
+ return false;
101
+ break;
102
+ case "between": // Inclusive on both ends
103
+ if(object[field] < test[t][0] || object[field] > test[t][1])
104
+ return false;
105
+ break;
106
+ case "includes": // Only works with String, Array
107
+ if(object[field].indexOf(test[t]) == -1)
108
+ return false;
109
+ break;
110
+ default:
111
+ ejsLog("Invalid condition for field " + field + ": " + t + " " + test[t], "ripple-error.log");
112
+ break;
113
+ }
114
+ }
115
+ return true;
116
+ },
117
+ /*
118
+ * Returns the mapped object without modification. Useful when
119
+ * preceded by map phases that do filtering or link phases.
120
+ */
121
+ mapIdentity: function(value, kd, arg){
122
+ return [value];
123
+ },
124
+ /*
125
+ * Returns the passed values without modification. Useful as an
126
+ * intermediary before reduce phases that require the entire
127
+ * result set to be present (limits).
128
+ */
129
+ reduceIdentity: function(values, arg){
130
+ return values;
131
+ }
132
+ };
@@ -0,0 +1,20 @@
1
+ require 'rails/generators/ripple_generator'
2
+
3
+ module Ripple
4
+ module Generators
5
+ class ModelGenerator < NamedBase
6
+ desc 'Creates a ripple model'
7
+ argument :attributes, :type => :array, :default => [], :banner => 'field:type field:type'
8
+ class_option :parent, :type => :string, :desc => "The parent class for the generated model"
9
+ class_option :embedded, :type => :boolean, :desc => "Make an embedded document model.", :default => false
10
+ class_option :embedded_in, :type => :string, :desc => "Specify the enclosing model for the embedded document. Implies --embedded."
11
+ check_class_collision
12
+
13
+ def create_model_file
14
+ template 'model.rb.erb', "app/models/#{file_path}.rb"
15
+ end
16
+
17
+ hook_for :test_framework
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent] %>
2
+ <% unless options[:parent] -%>
3
+ include Ripple::<%= "Embedded" if options[:embedded] || options[:embedded_in] %>Document
4
+ <% if options[:embedded_in] -%>embedded_in :<%= options[:embedded_in].underscore %><% end -%>
5
+ <% end -%>
6
+
7
+ <% attributes.reject{|attr| attr.reference?}.each do |attribute| -%>
8
+ property :<%= attribute.name %>, <%= attribute.type_class %>
9
+ <% end -%>
10
+ end
@@ -0,0 +1,16 @@
1
+ require 'rails/generators/ripple_generator'
2
+
3
+ module Ripple
4
+ module Generators
5
+ class ObserverGenerator < NamedBase
6
+ desc 'Creates an observer for Ripple documents'
7
+ check_class_collision :suffix => "Observer"
8
+
9
+ def create_observer_file
10
+ template 'observer.rb.erb', File.join("app/models", class_path, "#{file_name}_observer.rb")
11
+ end
12
+
13
+ hook_for :test_framework
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,2 @@
1
+ class <%= class_name %>Observer < ActiveModel::Observer
2
+ end
@@ -0,0 +1,7 @@
1
+ require 'ripple/test_server'
2
+
3
+ After do
4
+ Ripple::TestServer.clear
5
+ end
6
+
7
+ Ripple::TestServer.setup