wyngle-ripple 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. data/.gitignore +35 -0
  2. data/Gemfile +17 -0
  3. data/Gemfile.lock +133 -0
  4. data/Gemfile.rails30 +3 -0
  5. data/Gemfile.rails31 +3 -0
  6. data/Gemfile.rails32 +3 -0
  7. data/Guardfile +17 -0
  8. data/LICENSE +16 -0
  9. data/README.markdown +166 -0
  10. data/RELEASE_NOTES.textile +286 -0
  11. data/Rakefile +63 -0
  12. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
  13. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +25 -0
  14. data/lib/rails/generators/ripple/js/js_generator.rb +13 -0
  15. data/lib/rails/generators/ripple/js/templates/js/contrib.js +63 -0
  16. data/lib/rails/generators/ripple/js/templates/js/iso8601.js +76 -0
  17. data/lib/rails/generators/ripple/js/templates/js/ripple.js +132 -0
  18. data/lib/rails/generators/ripple/model/model_generator.rb +20 -0
  19. data/lib/rails/generators/ripple/model/templates/model.rb.erb +10 -0
  20. data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
  21. data/lib/rails/generators/ripple/observer/templates/observer.rb.erb +2 -0
  22. data/lib/rails/generators/ripple/test/templates/cucumber.rb.erb +7 -0
  23. data/lib/rails/generators/ripple/test/test_generator.rb +45 -0
  24. data/lib/rails/generators/ripple_generator.rb +79 -0
  25. data/lib/ripple.rb +86 -0
  26. data/lib/ripple/associations.rb +380 -0
  27. data/lib/ripple/associations/embedded.rb +35 -0
  28. data/lib/ripple/associations/instantiators.rb +26 -0
  29. data/lib/ripple/associations/linked.rb +65 -0
  30. data/lib/ripple/associations/many.rb +38 -0
  31. data/lib/ripple/associations/many_embedded_proxy.rb +39 -0
  32. data/lib/ripple/associations/many_linked_proxy.rb +66 -0
  33. data/lib/ripple/associations/many_reference_proxy.rb +95 -0
  34. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  35. data/lib/ripple/associations/one.rb +20 -0
  36. data/lib/ripple/associations/one_embedded_proxy.rb +35 -0
  37. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  38. data/lib/ripple/associations/one_linked_proxy.rb +26 -0
  39. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  40. data/lib/ripple/associations/proxy.rb +118 -0
  41. data/lib/ripple/attribute_methods.rb +132 -0
  42. data/lib/ripple/attribute_methods/dirty.rb +59 -0
  43. data/lib/ripple/attribute_methods/query.rb +34 -0
  44. data/lib/ripple/attribute_methods/read.rb +28 -0
  45. data/lib/ripple/attribute_methods/write.rb +25 -0
  46. data/lib/ripple/callbacks.rb +71 -0
  47. data/lib/ripple/conflict/basic_resolver.rb +86 -0
  48. data/lib/ripple/conflict/document_hooks.rb +46 -0
  49. data/lib/ripple/conflict/resolver.rb +96 -0
  50. data/lib/ripple/conflict/test_helper.rb +34 -0
  51. data/lib/ripple/conversion.rb +29 -0
  52. data/lib/ripple/core_ext.rb +3 -0
  53. data/lib/ripple/core_ext/casting.rb +151 -0
  54. data/lib/ripple/core_ext/indexes.rb +89 -0
  55. data/lib/ripple/core_ext/object.rb +8 -0
  56. data/lib/ripple/document.rb +105 -0
  57. data/lib/ripple/document/bucket_access.rb +25 -0
  58. data/lib/ripple/document/finders.rb +131 -0
  59. data/lib/ripple/document/key.rb +35 -0
  60. data/lib/ripple/document/link.rb +30 -0
  61. data/lib/ripple/document/persistence.rb +130 -0
  62. data/lib/ripple/embedded_document.rb +63 -0
  63. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  64. data/lib/ripple/embedded_document/finders.rb +26 -0
  65. data/lib/ripple/embedded_document/persistence.rb +75 -0
  66. data/lib/ripple/i18n.rb +5 -0
  67. data/lib/ripple/indexes.rb +151 -0
  68. data/lib/ripple/inspection.rb +32 -0
  69. data/lib/ripple/locale/en.yml +26 -0
  70. data/lib/ripple/locale/fr.yml +24 -0
  71. data/lib/ripple/nested_attributes.rb +275 -0
  72. data/lib/ripple/observable.rb +28 -0
  73. data/lib/ripple/properties.rb +74 -0
  74. data/lib/ripple/property_type_mismatch.rb +12 -0
  75. data/lib/ripple/railtie.rb +26 -0
  76. data/lib/ripple/railties/ripple.rake +68 -0
  77. data/lib/ripple/serialization.rb +82 -0
  78. data/lib/ripple/test_server.rb +35 -0
  79. data/lib/ripple/timestamps.rb +25 -0
  80. data/lib/ripple/translation.rb +18 -0
  81. data/lib/ripple/validations.rb +65 -0
  82. data/lib/ripple/validations/associated_validator.rb +43 -0
  83. data/lib/ripple/version.rb +3 -0
  84. data/ripple.gemspec +29 -0
  85. data/spec/fixtures/config.yml +8 -0
  86. data/spec/generators/ripple/configuration_generator_spec.rb +9 -0
  87. data/spec/generators/ripple/js_generator_spec.rb +14 -0
  88. data/spec/generators/ripple/model_generator_spec.rb +64 -0
  89. data/spec/generators/ripple/observer_generator_spec.rb +20 -0
  90. data/spec/generators/ripple/test_generator_spec.rb +118 -0
  91. data/spec/generators/ripple_generator_spec.rb +11 -0
  92. data/spec/integration/ripple/associations_spec.rb +164 -0
  93. data/spec/integration/ripple/conflict_resolution_spec.rb +329 -0
  94. data/spec/integration/ripple/indexes_spec.rb +47 -0
  95. data/spec/integration/ripple/nested_attributes_spec.rb +261 -0
  96. data/spec/integration/ripple/persistence_spec.rb +36 -0
  97. data/spec/integration/ripple/search_associations_spec.rb +31 -0
  98. data/spec/ripple/associations/many_embedded_proxy_spec.rb +119 -0
  99. data/spec/ripple/associations/many_linked_proxy_spec.rb +191 -0
  100. data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
  101. data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
  102. data/spec/ripple/associations/one_embedded_proxy_spec.rb +125 -0
  103. data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
  104. data/spec/ripple/associations/one_linked_proxy_spec.rb +91 -0
  105. data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
  106. data/spec/ripple/associations/proxy_spec.rb +84 -0
  107. data/spec/ripple/associations_spec.rb +153 -0
  108. data/spec/ripple/attribute_methods/dirty_spec.rb +80 -0
  109. data/spec/ripple/attribute_methods_spec.rb +286 -0
  110. data/spec/ripple/bucket_access_spec.rb +25 -0
  111. data/spec/ripple/callbacks_spec.rb +195 -0
  112. data/spec/ripple/conflict/resolver_spec.rb +42 -0
  113. data/spec/ripple/conversion_spec.rb +14 -0
  114. data/spec/ripple/core_ext_spec.rb +181 -0
  115. data/spec/ripple/document/link_spec.rb +67 -0
  116. data/spec/ripple/document_spec.rb +96 -0
  117. data/spec/ripple/embedded_document/finders_spec.rb +29 -0
  118. data/spec/ripple/embedded_document/persistence_spec.rb +80 -0
  119. data/spec/ripple/embedded_document_spec.rb +84 -0
  120. data/spec/ripple/finders_spec.rb +220 -0
  121. data/spec/ripple/indexes_spec.rb +111 -0
  122. data/spec/ripple/inspection_spec.rb +51 -0
  123. data/spec/ripple/key_spec.rb +31 -0
  124. data/spec/ripple/observable_spec.rb +120 -0
  125. data/spec/ripple/persistence_spec.rb +351 -0
  126. data/spec/ripple/properties_spec.rb +262 -0
  127. data/spec/ripple/ripple_spec.rb +71 -0
  128. data/spec/ripple/serialization_spec.rb +51 -0
  129. data/spec/ripple/timestamps_spec.rb +83 -0
  130. data/spec/ripple/validations/associated_validator_spec.rb +77 -0
  131. data/spec/ripple/validations_spec.rb +102 -0
  132. data/spec/spec_helper.rb +39 -0
  133. data/spec/support/associations.rb +1 -0
  134. data/spec/support/associations/proxies.rb +17 -0
  135. data/spec/support/generator_setup.rb +26 -0
  136. data/spec/support/integration_setup.rb +11 -0
  137. data/spec/support/models.rb +35 -0
  138. data/spec/support/models/address.rb +10 -0
  139. data/spec/support/models/box.rb +13 -0
  140. data/spec/support/models/car.rb +41 -0
  141. data/spec/support/models/cardboard_box.rb +2 -0
  142. data/spec/support/models/clock.rb +10 -0
  143. data/spec/support/models/clock_observer.rb +2 -0
  144. data/spec/support/models/company.rb +23 -0
  145. data/spec/support/models/credit_card.rb +5 -0
  146. data/spec/support/models/customer.rb +3 -0
  147. data/spec/support/models/email.rb +3 -0
  148. data/spec/support/models/family.rb +16 -0
  149. data/spec/support/models/favorite.rb +3 -0
  150. data/spec/support/models/indexer.rb +26 -0
  151. data/spec/support/models/invoice.rb +6 -0
  152. data/spec/support/models/late_invoice.rb +2 -0
  153. data/spec/support/models/nested.rb +12 -0
  154. data/spec/support/models/ninja.rb +7 -0
  155. data/spec/support/models/note.rb +4 -0
  156. data/spec/support/models/page.rb +3 -0
  157. data/spec/support/models/paid_invoice.rb +3 -0
  158. data/spec/support/models/post.rb +13 -0
  159. data/spec/support/models/profile.rb +7 -0
  160. data/spec/support/models/subscription.rb +26 -0
  161. data/spec/support/models/tasks.rb +9 -0
  162. data/spec/support/models/team.rb +11 -0
  163. data/spec/support/models/transactions.rb +17 -0
  164. data/spec/support/models/tree.rb +3 -0
  165. data/spec/support/models/user.rb +19 -0
  166. data/spec/support/models/widget.rb +23 -0
  167. data/spec/support/search.rb +14 -0
  168. data/spec/support/test_server.rb +39 -0
  169. data/spec/support/test_server.yml.example +14 -0
  170. metadata +434 -0
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rubygems/package_task'
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+
6
+ def gemspec
7
+ $ripple_gemspec ||= Gem::Specification.load("ripple.gemspec")
8
+ end
9
+
10
+ Gem::PackageTask.new(gemspec) do |pkg|
11
+ pkg.need_zip = false
12
+ pkg.need_tar = false
13
+ end
14
+
15
+ task :gem => :gemspec
16
+
17
+ desc %{Validate the gemspec file.}
18
+ task :gemspec do
19
+ gemspec.validate
20
+ end
21
+
22
+ desc %{Release the gem to RubyGems.org}
23
+ task :release => :gem do
24
+ system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
25
+ end
26
+
27
+ desc "Cleans up white space in source files"
28
+ task :clean_whitespace do
29
+ no_file_cleaned = true
30
+
31
+ Dir["**/*.rb"].each do |file|
32
+ contents = File.read(file)
33
+ cleaned_contents = contents.gsub(/([ \t]+)$/, '')
34
+ unless cleaned_contents == contents
35
+ no_file_cleaned = false
36
+ puts " - Cleaned #{file}"
37
+ File.open(file, 'w') { |f| f.write(cleaned_contents) }
38
+ end
39
+ end
40
+
41
+ if no_file_cleaned
42
+ puts "No files with trailing whitespace found"
43
+ end
44
+ end
45
+
46
+ desc "Run Unit Specs Only"
47
+ RSpec::Core::RakeTask.new(:spec) do |spec|
48
+ spec.rspec_opts = %w[--profile --tag ~integration]
49
+ end
50
+
51
+ namespace :spec do
52
+ desc "Run Integration Specs Only"
53
+ RSpec::Core::RakeTask.new(:integration) do |spec|
54
+ spec.rspec_opts = %w[--profile --tag integration]
55
+ end
56
+
57
+ desc "Run All Specs"
58
+ RSpec::Core::RakeTask.new(:all) do |spec|
59
+ spec.rspec_opts = %w[--profile]
60
+ end
61
+ end
62
+
63
+ task :default => "spec:all"
@@ -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