ripple 0.9.0.beta → 0.9.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,16 +1,17 @@
1
- source :gemcutter
1
+ source :rubygems
2
2
 
3
3
  gem 'bundler'
4
4
  gem 'riak-client', :path => "../riak-client"
5
5
  gem 'activemodel', '~>3.0.0'
6
- gem 'rspec', '~>2.0.0'
6
+ gem 'rspec', '~>2.4.0'
7
7
  gem 'tzinfo'
8
8
  gem 'rake'
9
9
 
10
- if defined? JRUBY_VERSION
10
+ platforms :mri do
11
+ gem 'yajl-ruby'
12
+ end
13
+
14
+ platforms :jruby do
11
15
  gem 'json'
12
16
  gem 'jruby-openssl'
13
- else
14
- gem 'yajl-ruby'
15
- gem 'curb', '>0.6'
16
17
  end
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ gemspec = Gem::Specification.new do |gem|
11
11
  gem.email = "sean@basho.com"
12
12
  gem.homepage = "http://seancribbs.github.com/ripple"
13
13
  gem.authors = ["Sean Cribbs"]
14
- gem.add_development_dependency "rspec", "~>2.0.0"
14
+ gem.add_development_dependency "rspec", "~>2.4.0"
15
15
  gem.add_dependency "riak-client", "~>#{version}"
16
16
  gem.add_dependency "activesupport", "~>3.0.0"
17
17
  gem.add_dependency "activemodel", "~>3.0.0"
@@ -23,10 +23,12 @@ gemspec = Gem::Specification.new do |gem|
23
23
  lib/rails/generators/ripple/configuration/templates/ripple.yml
24
24
  lib/rails/generators/ripple/js/js_generator.rb
25
25
  lib/rails/generators/ripple/js/templates/js/contrib.js
26
+ lib/rails/generators/ripple/js/templates/js/iso8601.js
26
27
  lib/rails/generators/ripple/js/templates/js/ripple.js
27
28
  lib/rails/generators/ripple/model/model_generator.rb
28
- lib/rails/generators/ripple/model/templates
29
29
  lib/rails/generators/ripple/model/templates/model.rb
30
+ lib/rails/generators/ripple/observer/observer_generator.rb
31
+ lib/rails/generators/ripple/observer/templates/observer.rb
30
32
  lib/rails/generators/ripple/test/templates/test_server.rb
31
33
  lib/rails/generators/ripple/test/test_generator.rb
32
34
  lib/rails/generators/ripple_generator.rb
@@ -60,9 +62,9 @@ gemspec = Gem::Specification.new do |gem|
60
62
  lib/ripple/embedded_document.rb
61
63
  lib/ripple/i18n.rb
62
64
  lib/ripple/inspection.rb
63
- lib/ripple/locale
64
65
  lib/ripple/locale/en.yml
65
66
  lib/ripple/nested_attributes.rb
67
+ lib/ripple/observable.rb
66
68
  lib/ripple/properties.rb
67
69
  lib/ripple/property_type_mismatch.rb
68
70
  lib/ripple/railtie.rb
@@ -95,6 +97,7 @@ gemspec = Gem::Specification.new do |gem|
95
97
  spec/ripple/finders_spec.rb
96
98
  spec/ripple/inspection_spec.rb
97
99
  spec/ripple/key_spec.rb
100
+ spec/ripple/observable_spec.rb
98
101
  spec/ripple/persistence_spec.rb
99
102
  spec/ripple/properties_spec.rb
100
103
  spec/ripple/ripple_spec.rb
@@ -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,30 @@
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
+ require 'rails/generators/ripple_generator'
16
+
17
+ module Ripple
18
+ module Generators
19
+ class ObserverGenerator < NamedBase
20
+ desc 'Creates an observer for Ripple documents'
21
+ check_class_collision :suffix => "Observer"
22
+
23
+ def create_observer_file
24
+ template 'observer.rb', File.join("app/models", class_path, "#{file_name}_observer.rb")
25
+ end
26
+
27
+ hook_for :test_framework
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Observer < ActiveModel::Observer
3
+ end
4
+ <% end -%>
@@ -8,7 +8,11 @@ module Ripple
8
8
  def test_server_config
9
9
  {
10
10
  :app_config => {
11
- :riak_kv => { :js_source_dir => Ripple.config.delete(:js_source_dir) },
11
+ :riak_kv => {
12
+ :js_source_dir => Ripple.config.delete(:js_source_dir),
13
+ :map_cache_size => 0, # 0.14
14
+ :vnode_cache_entries => 0 # 0.13
15
+ },
12
16
  :riak_core => { :web_port => Ripple.config[:port] || 8098 }
13
17
  },
14
18
  :bin_dir => Ripple.config.delete(:bin_dir),
@@ -33,6 +33,8 @@ module Ripple
33
33
  include Query
34
34
  include Dirty
35
35
  include ActiveModel::MassAssignmentSecurity
36
+
37
+ attr_protected :key
36
38
  end
37
39
 
38
40
  module ClassMethods
@@ -55,17 +57,17 @@ module Ripple
55
57
  # nor embedded documents.
56
58
  # @return [Hash] all document attributes, by key
57
59
  def attributes
58
- self.class.properties.values.inject({}) do |hash, prop|
60
+ self.class.properties.values.inject(@attributes.with_indifferent_access) do |hash, prop|
59
61
  hash[prop.key] = attribute(prop.key)
60
62
  hash
61
- end.with_indifferent_access
63
+ end
62
64
  end
63
65
 
64
66
  # Mass assign the document's attributes.
65
67
  # @param [Hash] attrs the attributes to assign
66
- def attributes=(attrs)
68
+ def attributes=(attrs, guard_protected_attrs = true)
67
69
  raise ArgumentError, t('attribute_hash') unless Hash === attrs
68
- sanitize_for_mass_assignment(attrs).each do |k,v|
70
+ (guard_protected_attrs ? sanitize_for_mass_assignment(attrs) : attrs).each do |k,v|
69
71
  next if k.to_sym == :key
70
72
  if respond_to?("#{k}=")
71
73
  __send__("#{k}=",v)
@@ -50,7 +50,7 @@ module Ripple
50
50
  # @private
51
51
  module InstanceMethods
52
52
  # @private
53
- def save(*args, &block)
53
+ def really_save(*args, &block)
54
54
  state = new? ? :create : :update
55
55
  run_callbacks(:save) do
56
56
  run_callbacks(state) do
@@ -97,7 +97,7 @@ FalseClass.module_eval(&boolean_cast)
97
97
  # @private
98
98
  class Time
99
99
  def as_json(options={})
100
- self.utc.rfc822
100
+ self.utc.send(Ripple.date_format)
101
101
  end
102
102
 
103
103
  def self.ripple_cast(value)
@@ -109,7 +109,7 @@ end
109
109
  # @private
110
110
  class Date
111
111
  def as_json(options={})
112
- self.to_s(:rfc822)
112
+ self.to_s(Ripple.date_format)
113
113
  end
114
114
 
115
115
  def self.ripple_cast(value)
@@ -121,7 +121,7 @@ end
121
121
  # @private
122
122
  class DateTime
123
123
  def as_json(options={})
124
- self.utc.to_s(:rfc822)
124
+ self.utc.to_s(Ripple.date_format)
125
125
  end
126
126
 
127
127
  def self.ripple_cast(value)
@@ -134,7 +134,7 @@ end
134
134
  module ActiveSupport
135
135
  class TimeWithZone
136
136
  def as_json(options={})
137
- self.utc.rfc822
137
+ self.utc.send(Ripple.date_format)
138
138
  end
139
139
  end
140
140
  end
@@ -14,7 +14,7 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
-
17
+
18
18
  # Raised by <tt>find!</tt> when a document cannot be found with the given key.
19
19
  # begin
20
20
  # Example.find!('badkey')
@@ -34,7 +34,7 @@ module Ripple
34
34
  end
35
35
  end
36
36
  end
37
-
37
+
38
38
  module Document
39
39
  module Finders
40
40
  extend ActiveSupport::Concern
@@ -60,7 +60,7 @@ module Ripple
60
60
  return find_one(args.first) if args.size == 1
61
61
  args.map {|key| find_one(key) }
62
62
  end
63
-
63
+
64
64
  # Retrieve single or multiple documents from Riak
65
65
  # but raise Ripple::DocumentNotFound if a key can
66
66
  # not be found in the bucket.
@@ -69,15 +69,15 @@ module Ripple
69
69
  raise DocumentNotFound.new(args, found) if !found || Array(found).include?(nil)
70
70
  found
71
71
  end
72
-
72
+
73
73
  # Find the first object using the first key in the
74
- # bucket's keys using find. You should not expect to
74
+ # bucket's keys using find. You should not expect to
75
75
  # actually get the first object you added to the bucket.
76
76
  # This is just a convenience method.
77
77
  def first
78
78
  find(bucket.keys.first)
79
79
  end
80
-
80
+
81
81
  # Find the first object using the first key in the
82
82
  # bucket's keys using find!
83
83
  def first!
@@ -112,15 +112,14 @@ module Ripple
112
112
  def find_one(key)
113
113
  instantiate(bucket.get(key, quorums.slice(:r)))
114
114
  rescue Riak::FailedRequest => fr
115
- return nil if fr.code.to_i == 404
116
- raise fr
115
+ raise fr unless fr.not_found?
117
116
  end
118
117
 
119
118
  def instantiate(robject)
120
119
  klass = robject.data['_type'].constantize rescue self
121
120
  klass.new.tap do |doc|
122
121
  doc.key = robject.key
123
- robject.data.except("_type").each {|k,v| doc.send("#{k}=", v) } if robject.data
122
+ doc.__send__(:attributes=, robject.data.except("_type"), false) if robject.data
124
123
  doc.instance_variable_set(:@new, false)
125
124
  doc.instance_variable_set(:@robject, robject)
126
125
  end
@@ -70,14 +70,16 @@ module Ripple
70
70
  # Saves the document in Riak.
71
71
  # @return [true,false] whether the document succeeded in saving
72
72
  def save(*args)
73
+ really_save(*args)
74
+ end
75
+
76
+ def really_save(*args)
73
77
  robject.key = key if robject.key != key
74
78
  robject.data = attributes_for_persistence
75
79
  robject.store(self.class.quorums.slice(:w,:dw))
76
80
  self.key = robject.key
77
81
  @new = false
78
82
  true
79
- rescue Riak::FailedRequest
80
- false
81
83
  end
82
84
 
83
85
  # Reloads the document from Riak
@@ -85,7 +87,7 @@ module Ripple
85
87
  def reload
86
88
  return self if new?
87
89
  robject.reload(:force => true)
88
- @robject.data.except("_type").each { |key, value| send("#{key}=", value) }
90
+ self.__send__(:attributes=, @robject.data.except("_type"), false)
89
91
  self
90
92
  end
91
93
 
@@ -0,0 +1,39 @@
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 'ripple'
15
+
16
+ module Ripple
17
+ module Observable
18
+ extend ActiveSupport::Concern
19
+ include ActiveModel::Observing
20
+
21
+ included do
22
+ set_callback(:create, :before) { notify_observers :before_create }
23
+ set_callback(:create, :after) { notify_observers :after_create }
24
+
25
+ set_callback(:update, :before) { notify_observers :before_update }
26
+ set_callback(:update, :after) { notify_observers :after_update }
27
+
28
+ set_callback(:save, :before) { notify_observers :before_save }
29
+ set_callback(:save, :after) { notify_observers :after_save }
30
+
31
+ set_callback(:destroy, :before) { notify_observers :before_destroy }
32
+ set_callback(:destroy, :after) { notify_observers :after_destroy }
33
+
34
+ set_callback(:validation, :before) { notify_observers :before_validation }
35
+ set_callback(:validation, :after) { notify_observers :after_validation }
36
+ end
37
+
38
+ end
39
+ end
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  require 'ripple'
15
+ require 'riak/util/translation'
15
16
 
16
17
  module Ripple
17
18
  # Adds i18n translation/string-lookup capabilities.
data/lib/ripple.rb CHANGED
@@ -18,6 +18,7 @@ require 'active_support/json'
18
18
  require 'active_model'
19
19
  require 'ripple/i18n'
20
20
  require 'ripple/core_ext'
21
+ require 'ripple/translation'
21
22
 
22
23
  # Contains the classes and modules related to the ODM built on top of
23
24
  # the basic Riak client.
@@ -46,12 +47,11 @@ module Ripple
46
47
 
47
48
  # Utilities
48
49
  autoload :Inspection
49
- autoload :Translation
50
50
 
51
51
  class << self
52
52
  # @return [Riak::Client] The client for the current thread.
53
53
  def client
54
- Thread.current[:ripple_client] ||= Riak::Client.new(config)
54
+ Thread.current[:ripple_client] ||= Riak::Client.new(client_config)
55
55
  end
56
56
 
57
57
  # Sets the client for the current thread.
@@ -71,6 +71,21 @@ module Ripple
71
71
  @config ||= {}
72
72
  end
73
73
 
74
+ # The format in which date/time objects will be serialized to
75
+ # strings in JSON. Defaults to :iso8601, and can be set in
76
+ # Ripple.config.
77
+ # @return [Symbol] the date format
78
+ def date_format
79
+ (config[:date_format] ||= :iso8601).to_sym
80
+ end
81
+
82
+ # Sets the format for date/time objects that are serialized to
83
+ # JSON.
84
+ # @param [Symbol] format the date format
85
+ def date_format=(format)
86
+ config[:date_format] = format.to_sym
87
+ end
88
+
74
89
  # Loads the Ripple configuration from a given YAML file.
75
90
  # Evaluates the configuration with ERB before loading.
76
91
  def load_configuration(config_file, config_keys = [:ripple])
@@ -82,6 +97,11 @@ module Ripple
82
97
  raise Ripple::MissingConfiguration.new(config_file)
83
98
  end
84
99
  alias_method :load_config, :load_configuration
100
+
101
+ private
102
+ def client_config
103
+ config.slice(:host, :port, :prefix, :mapred, :client_id, :http_backend, :solr)
104
+ end
85
105
  end
86
106
 
87
107
  # Exception raised when the path passed to
data/ripple.gemspec CHANGED
@@ -2,38 +2,37 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{ripple}
5
- s.version = "0.9.0.beta"
5
+ s.version = "0.9.0.beta2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Sean Cribbs"]
9
- s.date = %q{2010-12-29}
9
+ s.date = %q{2011-03-28}
10
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
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"]
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/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", "lib/rails/generators/ripple/observer/observer_generator.rb", "lib/rails/generators/ripple/observer/templates/observer.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/observable.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/observable_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
13
  s.homepage = %q{http://seancribbs.github.com/ripple}
14
14
  s.require_paths = ["lib"]
15
- s.rubygems_version = %q{1.3.7}
15
+ s.rubygems_version = %q{1.6.1}
16
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"]
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/observable_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
18
 
19
19
  if s.respond_to? :specification_version then
20
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
21
20
  s.specification_version = 3
22
21
 
23
22
  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.9.0.beta"])
23
+ s.add_development_dependency(%q<rspec>, ["~> 2.4.0"])
24
+ s.add_runtime_dependency(%q<riak-client>, ["~> 0.9.0.beta2"])
26
25
  s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.0"])
27
26
  s.add_runtime_dependency(%q<activemodel>, ["~> 3.0.0"])
28
27
  else
29
- s.add_dependency(%q<rspec>, ["~> 2.0.0"])
30
- s.add_dependency(%q<riak-client>, ["~> 0.9.0.beta"])
28
+ s.add_dependency(%q<rspec>, ["~> 2.4.0"])
29
+ s.add_dependency(%q<riak-client>, ["~> 0.9.0.beta2"])
31
30
  s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
32
31
  s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
33
32
  end
34
33
  else
35
- s.add_dependency(%q<rspec>, ["~> 2.0.0"])
36
- s.add_dependency(%q<riak-client>, ["~> 0.9.0.beta"])
34
+ s.add_dependency(%q<rspec>, ["~> 2.4.0"])
35
+ s.add_dependency(%q<riak-client>, ["~> 0.9.0.beta2"])
37
36
  s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
38
37
  s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
39
38
  end
@@ -75,4 +75,4 @@ describe Ripple::Associations::Proxy do
75
75
  it { should be_blank }
76
76
  it { should_not be_present }
77
77
  end
78
- end
78
+ end
@@ -185,8 +185,20 @@ describe Ripple::AttributeMethods do
185
185
  lambda { @widget.attributes = nil }.should raise_error(ArgumentError)
186
186
  end
187
187
 
188
- it "should protect attributes from mass assignment" do
188
+ it "should protect attributes from mass assignment when initialized" do
189
189
  @widget = Widget.new(:manufactured => true)
190
190
  @widget.manufactured.should be_false
191
191
  end
192
+
193
+ it "should protect attributes from mass assignment by default" do
194
+ @widget = Widget.new
195
+ @widget.attributes = { :manufactured => true }
196
+ @widget.manufactured.should be_false
197
+ end
198
+
199
+ it "should allow protected attributes to be mass assigned" do
200
+ @widget = Widget.new
201
+ @widget.send(:attributes=, { :manufactured => true }, false)
202
+ @widget.manufactured.should be_true
203
+ end
192
204
  end
@@ -77,6 +77,15 @@ describe Ripple::Callbacks do
77
77
  @box.destroy
78
78
  end
79
79
 
80
+ it "should call save and validate callbacks in the correct order" do
81
+ Box.before_validation { $pinger.ping(:v) }
82
+ Box.before_save { $pinger.ping(:s) }
83
+ $pinger.should_receive(:ping).with(:v).ordered
84
+ $pinger.should_receive(:ping).with(:s).ordered
85
+ @box = Box.new
86
+ @box.save
87
+ end
88
+
80
89
  describe "validation callbacks" do
81
90
  it "should call validation callbacks" do
82
91
  Box.before_validation { $pinger.ping }
@@ -14,35 +14,86 @@
14
14
  require File.expand_path("../../spec_helper", __FILE__)
15
15
 
16
16
  describe Time do
17
- it "serializes to JSON in UTC, RFC 822 format" do
17
+ before { @date_format = Ripple.date_format }
18
+ after { Ripple.date_format = @date_format }
19
+
20
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
21
+ Time.utc(2010,3,16,12).as_json.should == "2010-03-16T12:00:00Z"
22
+ end
23
+
24
+ it "serializes to JSON in UTC, RFC822 format when specified" do
25
+ Ripple.date_format = :rfc822
18
26
  Time.utc(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
19
27
  end
20
28
  end
21
29
 
22
30
  describe Date do
23
- it "serializes to JSON RFC 822 format" do
31
+ before { @date_format = Ripple.date_format }
32
+ after { Ripple.date_format = @date_format }
33
+
34
+ it "serializes to JSON ISO 8601 format by default" do
35
+ Date.civil(2010,3,16).as_json.should == "2010-03-16"
36
+ end
37
+
38
+ it "serializes to JSON in UTC, RFC822 format when specified" do
39
+ Ripple.date_format = :rfc822
24
40
  Date.civil(2010,3,16).as_json.should == "16 Mar 2010"
25
41
  end
26
42
  end
27
43
 
28
44
  describe DateTime do
45
+ before { @date_format = Ripple.date_format }
46
+ after { Ripple.date_format = @date_format }
47
+
29
48
  before :each do
30
49
  Time.zone = :utc
31
50
  end
32
51
 
33
- it "serializes to JSON in UTC, RFC 822 format" do
52
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
53
+ DateTime.civil(2010,3,16,12).as_json.should == "2010-03-16T12:00:00+00:00"
54
+ end
55
+
56
+ it "serializes to JSON in UTC, RFC822 format when specified" do
57
+ Ripple.date_format = :rfc822
34
58
  DateTime.civil(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 +0000"
35
59
  end
36
60
  end
37
61
 
38
62
  describe ActiveSupport::TimeWithZone do
39
- it "serializes to JSON in UTC, RFC 822 format" do
63
+ before { @date_format = Ripple.date_format }
64
+ after { Ripple.date_format = @date_format }
65
+
66
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
67
+ time = Time.utc(2010,3,16,12)
68
+ zone = ActiveSupport::TimeZone['Alaska']
69
+ ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "2010-03-16T12:00:00Z"
70
+ end
71
+
72
+ it "serializes to JSON in UTC, RFC822 format when specified" do
73
+ Ripple.date_format = :rfc822
40
74
  time = Time.utc(2010,3,16,12)
41
75
  zone = ActiveSupport::TimeZone['Alaska']
42
76
  ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
43
77
  end
44
78
  end
45
79
 
80
+ describe String do
81
+ it "can parse RFC 822 and ISO 8601 times" do
82
+ 'Tue, 16 Mar 2010 12:00:00 -0000'.to_time.should == Time.utc(2010,3,16,12)
83
+ '2010-03-16T12:00:00Z'.to_time.should == Time.utc(2010,3,16,12)
84
+ end
85
+
86
+ it "can parse RFC 822 and ISO 8601 dates" do
87
+ '16 Mar 2010'.to_date.should == Date.civil(2010,3,16)
88
+ '2010-3-16'.to_date.should == Date.civil(2010,3,16)
89
+ end
90
+
91
+ it "can parse RFC 822 and ISO 8601 datetimes" do
92
+ 'Tue, 16 Mar 2010 12:00:00 +0000'.to_datetime.should == DateTime.civil(2010,3,16,12)
93
+ '2010-03-16T12:00:00+00:00'.to_datetime.should == DateTime.civil(2010,3,16,12)
94
+ end
95
+ end
96
+
46
97
  describe "Boolean" do
47
98
  it "should be available to properties on documents" do
48
99
  lambda {
@@ -75,9 +75,11 @@ describe Ripple::Document::Finders do
75
75
  lambda { Box.find!("square") }.should_not raise_error(Ripple::DocumentNotFound)
76
76
  end
77
77
 
78
- it "should raise an exception when finding an existing document that has properties we don't know about" do
79
- @plain.raw_data = '{"non_existent_property":"whatever"}'
80
- lambda { Box.find("square") }.should raise_error
78
+ it "should put properties we don't know about into the attributes" do
79
+ @plain.raw_data = '{"non_existent_property":"some_value"}'
80
+ box = Box.find("square")
81
+ box[:non_existent_property].should == "some_value"
82
+ box.should_not respond_to(:non_existent_property)
81
83
  end
82
84
 
83
85
  it "should return the document when calling find!" do
@@ -86,18 +88,18 @@ describe Ripple::Document::Finders do
86
88
  end
87
89
 
88
90
  it "should return nil when no object exists at that key" do
89
- @bucket.should_receive(:get).with("square", {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
91
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
90
92
  box = Box.find("square")
91
93
  box.should be_nil
92
94
  end
93
95
 
94
96
  it "should raise DocumentNotFound when using find! if no object exists at that key" do
95
- @bucket.should_receive(:get).with("square", {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
97
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
96
98
  lambda { Box.find!("square") }.should raise_error(Ripple::DocumentNotFound, "Couldn't find document with key: square")
97
99
  end
98
100
 
99
101
  it "should re-raise the failed request exception if not a 404" do
100
- @bucket.should_receive(:get).with("square", {}).and_raise(Riak::FailedRequest.new(:get, 200, 500, {}, "500 internal server error"))
102
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 500, {}, "500 internal server error"))
101
103
  lambda { Box.find("square") }.should raise_error(Riak::FailedRequest)
102
104
  end
103
105
 
@@ -123,7 +125,7 @@ describe Ripple::Document::Finders do
123
125
  describe "when using find with missing keys" do
124
126
  before :each do
125
127
  @bucket.should_receive(:get).with("square", {}).and_return(@plain)
126
- @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
128
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
127
129
  end
128
130
 
129
131
  it "should return nil for documents that no longer exist" do
@@ -153,7 +155,7 @@ describe Ripple::Document::Finders do
153
155
  it "should exclude objects that are not found" do
154
156
  @bucket.should_receive(:keys).and_return(["square", "rectangle"])
155
157
  @bucket.should_receive(:get).with("square", {}).and_return(@plain)
156
- @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
158
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
157
159
  boxes = Box.all
158
160
  boxes.should have(1).item
159
161
  boxes.first.shape.should == "square"
@@ -162,7 +164,7 @@ describe Ripple::Document::Finders do
162
164
  it "should yield found objects to the passed block, excluding missing objects, and return an empty array" do
163
165
  @bucket.should_receive(:keys).and_yield(["square"]).and_yield(["rectangle"])
164
166
  @bucket.should_receive(:get).with("square", {}).and_return(@plain)
165
- @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
167
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
166
168
  @block = mock()
167
169
  @block.should_receive(:ping).once
168
170
  Box.all do |box|
@@ -0,0 +1,134 @@
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 File.expand_path("../../spec_helper", __FILE__)
15
+
16
+ describe Ripple::Observable do
17
+ require 'support/models/clock'
18
+ require 'support/models/clock_observer'
19
+
20
+ before :each do
21
+ @client = Ripple.client
22
+ @backend = mock("Backend", :store_object => true)
23
+ @client.stub!(:backend).and_return(@backend)
24
+ @clock = Clock.new
25
+ @observer = ClockObserver.instance
26
+ end
27
+
28
+ context "given a document is created" do
29
+ it "should notify all observers twice" do
30
+ Clock.should_receive(:notify_observers).exactly(6).times
31
+ @clock.save
32
+ end
33
+
34
+ context "before creating the document" do
35
+ it "should call Observer#before_create" do
36
+ @observer.should_receive(:before_create)
37
+ @clock.save
38
+ end
39
+
40
+ it "should call Observer#before_save" do
41
+ @observer.should_receive(:before_save)
42
+ @clock.save
43
+ end
44
+
45
+ it "should call Observer#before_validation" do
46
+ @observer.should_receive(:before_validation)
47
+ @clock.save
48
+ end
49
+ end
50
+
51
+ context "after creating the document" do
52
+ it "should call Observer#after_create" do
53
+ @observer.should_receive(:after_create)
54
+ @clock.save
55
+ end
56
+
57
+ it "should call Observer#after_save" do
58
+ @observer.should_receive(:after_save)
59
+ @clock.save
60
+ end
61
+
62
+ it "should call Observer#after_validation" do
63
+ @observer.should_receive(:after_validation)
64
+ @clock.save
65
+ end
66
+ end
67
+ end
68
+
69
+ context "given a document is updated" do
70
+ before(:each) do
71
+ @clock.stub!(:new?).and_return(false)
72
+ end
73
+
74
+ it "should notify all observers twice" do
75
+ Clock.should_receive(:notify_observers).exactly(6).times
76
+ @clock.save
77
+ end
78
+
79
+ context "before updating the document" do
80
+ it "should call Observer#before_update" do
81
+ @observer.should_receive(:before_update)
82
+ @clock.save
83
+ end
84
+
85
+ it "should call Observer#before_save" do
86
+ @observer.should_receive(:before_save)
87
+ @clock.save
88
+ end
89
+
90
+ it "should call Observer#before_validation" do
91
+ @observer.should_receive(:before_validation)
92
+ @clock.save
93
+ end
94
+ end
95
+
96
+ context "after updating the document" do
97
+ it "should call Observer#after_update" do
98
+ @observer.should_receive(:after_update)
99
+ @clock.save
100
+ end
101
+
102
+ it "should call Observer#after_save" do
103
+ @observer.should_receive(:after_save)
104
+ @clock.save
105
+ end
106
+
107
+ it "should call Observer#after_validation" do
108
+ @observer.should_receive(:after_validation)
109
+ @clock.save
110
+ end
111
+ end
112
+ end
113
+
114
+ context "given a document is destroyed" do
115
+ it "should notify all observers twice" do
116
+ Clock.should_receive(:notify_observers).twice
117
+ @clock.destroy
118
+ end
119
+
120
+ context "before destroying the document" do
121
+ it "should call Observer#before_destroy" do
122
+ @observer.should_receive(:before_destroy)
123
+ @clock.destroy
124
+ end
125
+ end
126
+
127
+ context "after destroy the document" do
128
+ it "should call Observer#after_destroy" do
129
+ @observer.should_receive(:after_destroy)
130
+ @clock.destroy
131
+ end
132
+ end
133
+ end
134
+ end
@@ -68,7 +68,7 @@ describe Ripple::Document::Persistence do
68
68
  end
69
69
 
70
70
  it "should instantiate and save a new object to riak" do
71
- json = @widget.attributes.merge(:size => 10, :shipped_at => "Sat, 01 Jan 2000 20:15:01 -0000", :_type => 'Widget').to_json
71
+ json = @widget.attributes.merge(:size => 10, :shipped_at => "2000-01-01T20:15:01Z", :_type => 'Widget').to_json
72
72
  @backend.should_receive(:store_object) do |obj, _, _, _|
73
73
  obj.raw_data.should == json
74
74
  obj.key.should be_nil
@@ -96,6 +96,28 @@ describe Ripple::Document::Persistence do
96
96
  @widget.should_not be_a_new_record
97
97
  end
98
98
 
99
+ it "should save the attributes not having a corresponding property" do
100
+ attrs = @widget.attributes.merge("_type" => "Widget", "unknown_property" => "a_value")
101
+ @backend.should_receive(:store_object) do |obj, _, _, _|
102
+ obj.data.should == attrs
103
+ obj.key.should be_nil
104
+ # Simulate loading the response with the key
105
+ obj.key = "new_widget"
106
+ end
107
+ @widget["unknown_property"] = "a_value"
108
+ @widget.save
109
+ @widget.key.should == "new_widget"
110
+ @widget.should_not be_a_new_record
111
+ @widget.changes.should be_blank
112
+ end
113
+
114
+ it "should allow unexpected exceptions to be raised" do
115
+ robject = mock("robject", :key => @widget.key, "data=" => true)
116
+ robject.should_receive(:store).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 404, {}, "404 not found"))
117
+ @widget.stub!(:robject).and_return(robject)
118
+ lambda { @widget.save }.should raise_error(Riak::FailedRequest)
119
+ end
120
+
99
121
  it "should reload a saved object" do
100
122
  json = @widget.attributes.merge(:_type => "Widget").to_json
101
123
  @backend.should_receive(:store_object) do |obj, _, _, _|
@@ -34,32 +34,51 @@ describe Ripple do
34
34
  Ripple.client = client
35
35
  Ripple.client.should == client
36
36
  end
37
-
37
+
38
38
  it "should reset the client when the configuration changes" do
39
39
  c = Ripple.client
40
40
  Ripple.config = {:port => 9000}
41
41
  Ripple.client.should_not == c
42
42
  Ripple.client.port.should == 9000
43
43
  end
44
-
44
+
45
45
  it "should raise No Such File or Directory when given a bad configuration file" do
46
46
  lambda { Ripple.load_config('not-here') }.should raise_error(Ripple::MissingConfiguration)
47
47
  end
48
-
48
+
49
49
  it "should pass an empty hash into configure if the configuration file is missing the key" do
50
50
  Ripple.should_receive(:config=).with({})
51
51
  Ripple.load_config(File.join(File.dirname(__FILE__), '..', 'fixtures', 'config.yml'), [:ripple, 'not-here'])
52
52
  end
53
-
53
+
54
54
  it "should select the configuration hash from the config keys provided" do
55
55
  Ripple.load_config(File.join(File.dirname(__FILE__), '..', 'fixtures', 'config.yml'), ['ripple_rails', 'development'])
56
56
  Ripple.client.port.should == 9001
57
57
  Ripple.client.host.should == '127.0.0.1'
58
58
  end
59
-
59
+
60
60
  it "should apply the configuration under the ripple key" do
61
61
  Ripple.load_config(File.join(File.dirname(__FILE__), '..', 'fixtures', 'config.yml'))
62
62
  Ripple.client.port.should == 9000
63
63
  Ripple.client.host.should == 'localhost'
64
64
  end
65
+
66
+ describe "date format" do
67
+ before { @date_format = Ripple.date_format }
68
+ after { Ripple.date_format = @date_format }
69
+
70
+ it "should default to :iso8601" do
71
+ Ripple.date_format.should == :iso8601
72
+ end
73
+
74
+ it "should allow setting via the config" do
75
+ Ripple.config = {"date_format" => "rfc822"}
76
+ Ripple.date_format.should == :rfc822
77
+ end
78
+
79
+ it "should allow setting manually" do
80
+ Ripple.date_format = "rfc822"
81
+ Ripple.date_format.should == :rfc822
82
+ end
83
+ end
65
84
  end
@@ -41,20 +41,20 @@ describe Ripple::Validations do
41
41
  @box.should_receive(:valid?).and_return(false)
42
42
  @box.save.should be_false
43
43
  end
44
-
44
+
45
45
  it "should allow skipping validations by passing save :validate => false" do
46
46
  Ripple.client.http.stub!(:perform).and_return(mock_response)
47
47
  @box.should_not_receive(:valid?)
48
48
  @box.save(:validate => false).should be_true
49
49
  end
50
-
50
+
51
51
  describe "when using save! on an invalid record" do
52
52
  before(:each) { @box.stub!(:valid?).and_return(false) }
53
-
53
+
54
54
  it "should raise DocumentInvalid" do
55
55
  lambda { @box.save! }.should raise_error(Ripple::DocumentInvalid)
56
56
  end
57
-
57
+
58
58
  it "should raise an exception that has the invalid document" do
59
59
  begin
60
60
  @box.save!
@@ -63,26 +63,34 @@ describe Ripple::Validations do
63
63
  end
64
64
  end
65
65
  end
66
-
66
+
67
67
  it "should not raise an error when save! is called and the document is valid" do
68
68
  @box.stub!(:save).and_return(true)
69
69
  @box.stub!(:valid?).and_return(true)
70
70
  lambda { @box.save! }.should_not raise_error(Ripple::DocumentInvalid)
71
71
  end
72
-
72
+
73
73
  it "should return true from save! when no exception is raised" do
74
74
  @box.stub!(:save).and_return(true)
75
75
  @box.stub!(:valid?).and_return(true)
76
76
  @box.save!.should be_true
77
77
  end
78
-
78
+
79
+ it "should allow unexpected exceptions to be raised" do
80
+ robject = mock("robject", :key => @box.key, "data=" => true)
81
+ robject.should_receive(:store).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 404, {}, "404 not found"))
82
+ @box.stub!(:robject).and_return(robject)
83
+ @box.stub!(:valid?).and_return(true)
84
+ lambda { @box.save! }.should raise_error(Riak::FailedRequest)
85
+ end
86
+
79
87
  it "should not raise an error when creating a box with create! succeeds" do
80
88
  @box.stub!(:new?).and_return(false)
81
89
  Box.stub(:create).and_return(@box)
82
90
  lambda { @new_box = Box.create! }.should_not raise_error(Ripple::DocumentInvalid)
83
91
  @new_box.should == @box
84
92
  end
85
-
93
+
86
94
  it "should raise an error when creating a box with create! fails" do
87
95
  @box.stub!(:new?).and_return(true)
88
96
  Box.stub(:create).and_return(@box)
@@ -102,8 +110,8 @@ describe Ripple::Validations do
102
110
  @box.should be_valid
103
111
  Box.properties.delete :size
104
112
  end
105
-
113
+
106
114
  after :each do
107
115
  Box.reset_callbacks(:validate)
108
- end
116
+ end
109
117
  end
metadata CHANGED
@@ -1,14 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ripple
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31098121
5
- prerelease: true
6
- segments:
7
- - 0
8
- - 9
9
- - 0
10
- - beta
11
- version: 0.9.0.beta
4
+ prerelease: 6
5
+ version: 0.9.0.beta2
12
6
  platform: ruby
13
7
  authors:
14
8
  - Sean Cribbs
@@ -16,7 +10,7 @@ autorequire:
16
10
  bindir: bin
17
11
  cert_chain: []
18
12
 
19
- date: 2010-12-29 00:00:00 -06:00
13
+ date: 2011-03-28 00:00:00 -04:00
20
14
  default_executable:
21
15
  dependencies:
22
16
  - !ruby/object:Gem::Dependency
@@ -27,12 +21,7 @@ dependencies:
27
21
  requirements:
28
22
  - - ~>
29
23
  - !ruby/object:Gem::Version
30
- hash: 15
31
- segments:
32
- - 2
33
- - 0
34
- - 0
35
- version: 2.0.0
24
+ version: 2.4.0
36
25
  type: :development
37
26
  version_requirements: *id001
38
27
  - !ruby/object:Gem::Dependency
@@ -43,13 +32,7 @@ dependencies:
43
32
  requirements:
44
33
  - - ~>
45
34
  - !ruby/object:Gem::Version
46
- hash: 31098121
47
- segments:
48
- - 0
49
- - 9
50
- - 0
51
- - beta
52
- version: 0.9.0.beta
35
+ version: 0.9.0.beta2
53
36
  type: :runtime
54
37
  version_requirements: *id002
55
38
  - !ruby/object:Gem::Dependency
@@ -60,11 +43,6 @@ dependencies:
60
43
  requirements:
61
44
  - - ~>
62
45
  - !ruby/object:Gem::Version
63
- hash: 7
64
- segments:
65
- - 3
66
- - 0
67
- - 0
68
46
  version: 3.0.0
69
47
  type: :runtime
70
48
  version_requirements: *id003
@@ -76,11 +54,6 @@ dependencies:
76
54
  requirements:
77
55
  - - ~>
78
56
  - !ruby/object:Gem::Version
79
- hash: 7
80
- segments:
81
- - 3
82
- - 0
83
- - 0
84
57
  version: 3.0.0
85
58
  type: :runtime
86
59
  version_requirements: *id004
@@ -98,9 +71,12 @@ files:
98
71
  - lib/rails/generators/ripple/configuration/templates/ripple.yml
99
72
  - lib/rails/generators/ripple/js/js_generator.rb
100
73
  - lib/rails/generators/ripple/js/templates/js/contrib.js
74
+ - lib/rails/generators/ripple/js/templates/js/iso8601.js
101
75
  - lib/rails/generators/ripple/js/templates/js/ripple.js
102
76
  - lib/rails/generators/ripple/model/model_generator.rb
103
77
  - lib/rails/generators/ripple/model/templates/model.rb
78
+ - lib/rails/generators/ripple/observer/observer_generator.rb
79
+ - lib/rails/generators/ripple/observer/templates/observer.rb
104
80
  - lib/rails/generators/ripple/test/templates/test_server.rb
105
81
  - lib/rails/generators/ripple/test/test_generator.rb
106
82
  - lib/rails/generators/ripple_generator.rb
@@ -136,6 +112,7 @@ files:
136
112
  - lib/ripple/inspection.rb
137
113
  - lib/ripple/locale/en.yml
138
114
  - lib/ripple/nested_attributes.rb
115
+ - lib/ripple/observable.rb
139
116
  - lib/ripple/properties.rb
140
117
  - lib/ripple/property_type_mismatch.rb
141
118
  - lib/ripple/railtie.rb
@@ -168,6 +145,7 @@ files:
168
145
  - spec/ripple/finders_spec.rb
169
146
  - spec/ripple/inspection_spec.rb
170
147
  - spec/ripple/key_spec.rb
148
+ - spec/ripple/observable_spec.rb
171
149
  - spec/ripple/persistence_spec.rb
172
150
  - spec/ripple/properties_spec.rb
173
151
  - spec/ripple/ripple_spec.rb
@@ -215,25 +193,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
215
193
  requirements:
216
194
  - - ">="
217
195
  - !ruby/object:Gem::Version
218
- hash: 3
219
- segments:
220
- - 0
221
196
  version: "0"
222
197
  required_rubygems_version: !ruby/object:Gem::Requirement
223
198
  none: false
224
199
  requirements:
225
200
  - - ">"
226
201
  - !ruby/object:Gem::Version
227
- hash: 25
228
- segments:
229
- - 1
230
- - 3
231
- - 1
232
202
  version: 1.3.1
233
203
  requirements: []
234
204
 
235
205
  rubyforge_project:
236
- rubygems_version: 1.3.7
206
+ rubygems_version: 1.6.1
237
207
  signing_key:
238
208
  specification_version: 3
239
209
  summary: ripple is an object-mapper library for Riak, the distributed database by Basho.
@@ -259,6 +229,7 @@ test_files:
259
229
  - spec/ripple/finders_spec.rb
260
230
  - spec/ripple/inspection_spec.rb
261
231
  - spec/ripple/key_spec.rb
232
+ - spec/ripple/observable_spec.rb
262
233
  - spec/ripple/persistence_spec.rb
263
234
  - spec/ripple/properties_spec.rb
264
235
  - spec/ripple/ripple_spec.rb