ripple 0.6.1 → 0.7.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 (110) hide show
  1. data/Rakefile +61 -48
  2. data/lib/ripple.rb +5 -1
  3. data/lib/ripple/core_ext/casting.rb +3 -0
  4. data/lib/ripple/document.rb +6 -2
  5. data/lib/ripple/document/associations.rb +154 -0
  6. data/lib/ripple/document/{persistence/callbacks.rb → associations/embedded.rb} +20 -24
  7. data/lib/ripple/document/associations/instantiators.rb +41 -0
  8. data/lib/{riak/util/translation.rb → ripple/document/associations/linked.rb} +14 -11
  9. data/lib/ripple/document/associations/many.rb +52 -0
  10. data/lib/ripple/document/associations/many_embedded_proxy.rb +49 -0
  11. data/lib/{riak/i18n.rb → ripple/document/associations/one.rb} +18 -2
  12. data/lib/ripple/document/associations/one_embedded_proxy.rb +41 -0
  13. data/lib/ripple/document/associations/proxy.rb +125 -0
  14. data/lib/ripple/document/attribute_methods.rb +8 -1
  15. data/lib/ripple/document/attribute_methods/read.rb +4 -0
  16. data/lib/ripple/document/attribute_methods/write.rb +4 -0
  17. data/lib/ripple/document/bucket_access.rb +1 -1
  18. data/lib/ripple/document/callbacks.rb +75 -0
  19. data/lib/ripple/document/finders.rb +50 -3
  20. data/lib/ripple/document/persistence.rb +14 -6
  21. data/lib/ripple/document/validations.rb +35 -7
  22. data/lib/ripple/document/validations/associated_validator.rb +37 -0
  23. data/lib/ripple/embedded_document.rb +8 -2
  24. data/lib/{riak/map_reduce_error.rb → ripple/embedded_document/conversion.rb} +19 -5
  25. data/lib/{riak/invalid_response.rb → ripple/embedded_document/finders.rb} +17 -8
  26. data/lib/ripple/embedded_document/persistence.rb +75 -13
  27. data/lib/ripple/locale/en.yml +7 -1
  28. data/{spec/riak/net_http_backend_spec.rb → lib/ripple/railtie.rb} +17 -13
  29. data/spec/fixtures/config.yml +3 -0
  30. data/spec/integration/ripple/associations_spec.rb +81 -0
  31. data/spec/integration/ripple/persistence_spec.rb +54 -0
  32. data/spec/ripple/associations/many_embedded_proxy_spec.rb +124 -0
  33. data/spec/ripple/associations/one_embedded_proxy_spec.rb +130 -0
  34. data/spec/ripple/associations/proxy_spec.rb +78 -0
  35. data/spec/ripple/associations_spec.rb +111 -0
  36. data/spec/ripple/attribute_methods_spec.rb +37 -16
  37. data/spec/ripple/bucket_access_spec.rb +3 -14
  38. data/spec/ripple/callbacks_spec.rb +53 -9
  39. data/spec/ripple/document_spec.rb +22 -6
  40. data/spec/ripple/embedded_document/conversion_spec.rb +35 -0
  41. data/spec/{riak/headers_spec.rb → ripple/embedded_document/finders_spec.rb} +17 -14
  42. data/spec/ripple/embedded_document/persistence_spec.rb +86 -0
  43. data/spec/ripple/embedded_document_spec.rb +1 -26
  44. data/spec/ripple/finders_spec.rb +66 -30
  45. data/spec/ripple/persistence_spec.rb +33 -21
  46. data/spec/ripple/properties_spec.rb +1 -7
  47. data/spec/ripple/ripple_spec.rb +10 -0
  48. data/spec/ripple/timestamps_spec.rb +12 -19
  49. data/spec/ripple/validations_spec.rb +48 -6
  50. data/spec/spec_helper.rb +4 -10
  51. data/spec/support/associations/proxies.rb +16 -0
  52. data/spec/support/integration.rb +4 -0
  53. data/spec/support/mocks.rb +3 -0
  54. data/spec/support/models/address.rb +8 -0
  55. data/spec/support/models/box.rb +6 -0
  56. data/spec/support/models/cardboard_box.rb +3 -0
  57. data/spec/support/models/clock.rb +6 -0
  58. data/spec/support/models/customer.rb +4 -0
  59. data/spec/support/models/email.rb +4 -0
  60. data/spec/support/models/family.rb +14 -0
  61. data/spec/support/models/favorite.rb +4 -0
  62. data/spec/support/models/invoice.rb +6 -0
  63. data/spec/support/models/late_invoice.rb +3 -0
  64. data/spec/support/models/note.rb +4 -0
  65. data/spec/support/models/page.rb +4 -0
  66. data/spec/support/models/paid_invoice.rb +4 -0
  67. data/spec/support/models/tree.rb +3 -0
  68. data/spec/support/models/user.rb +6 -0
  69. data/spec/support/models/widget.rb +6 -0
  70. metadata +111 -138
  71. data/.document +0 -5
  72. data/.gitignore +0 -26
  73. data/CONTRIBUTORS.textile +0 -5
  74. data/LICENSE +0 -13
  75. data/README.textile +0 -128
  76. data/RELEASE_NOTES.textile +0 -68
  77. data/VERSION +0 -1
  78. data/lib/riak.rb +0 -46
  79. data/lib/riak/bucket.rb +0 -157
  80. data/lib/riak/client.rb +0 -139
  81. data/lib/riak/client/curb_backend.rb +0 -82
  82. data/lib/riak/client/http_backend.rb +0 -209
  83. data/lib/riak/client/net_http_backend.rb +0 -49
  84. data/lib/riak/failed_request.rb +0 -37
  85. data/lib/riak/link.rb +0 -73
  86. data/lib/riak/locale/en.yml +0 -37
  87. data/lib/riak/map_reduce.rb +0 -248
  88. data/lib/riak/robject.rb +0 -258
  89. data/lib/riak/util/escape.rb +0 -12
  90. data/lib/riak/util/fiber1.8.rb +0 -48
  91. data/lib/riak/util/headers.rb +0 -44
  92. data/lib/riak/util/multipart.rb +0 -52
  93. data/lib/riak/walk_spec.rb +0 -117
  94. data/ripple.gemspec +0 -169
  95. data/spec/fixtures/cat.jpg +0 -0
  96. data/spec/fixtures/multipart-blank.txt +0 -7
  97. data/spec/fixtures/multipart-with-body.txt +0 -16
  98. data/spec/riak/bucket_spec.rb +0 -230
  99. data/spec/riak/client_spec.rb +0 -174
  100. data/spec/riak/curb_backend_spec.rb +0 -50
  101. data/spec/riak/escape_spec.rb +0 -17
  102. data/spec/riak/http_backend_spec.rb +0 -131
  103. data/spec/riak/link_spec.rb +0 -82
  104. data/spec/riak/map_reduce_spec.rb +0 -352
  105. data/spec/riak/multipart_spec.rb +0 -36
  106. data/spec/riak/object_spec.rb +0 -532
  107. data/spec/riak/walk_spec_spec.rb +0 -208
  108. data/spec/spec.opts +0 -1
  109. data/spec/support/http_backend_implementation_examples.rb +0 -215
  110. data/spec/support/mock_server.rb +0 -58
data/Rakefile CHANGED
@@ -1,61 +1,74 @@
1
1
  require 'rubygems'
2
- require 'rake'
3
- require 'rake/clean'
4
-
5
- begin
6
- require 'jeweler'
7
- Jeweler::Tasks.new do |gem|
8
- gem.name = "ripple"
9
- gem.summary = %Q{ripple is a rich Ruby client for Riak, Basho's distributed database.}
10
- gem.description = %Q{ripple is a rich Ruby client for Riak, Basho's distributed database. It includes all the basics of accessing and manipulating Riak buckets and objects, and an object mapper library for building a rich domain on top of Riak.}
11
- gem.email = "seancribbs@gmail.com"
12
- gem.homepage = "http://seancribbs.github.com/ripple"
13
- gem.authors = ["Sean Cribbs"]
14
- gem.add_development_dependency "rspec", ">= 1.3"
15
- gem.add_development_dependency "fakeweb", ">=1.2"
16
- gem.add_development_dependency "rack", ">=1.0"
17
- gem.add_development_dependency "yard", ">=0.5.2"
18
- gem.add_development_dependency "curb", ">=0.6"
19
- gem.add_dependency "activesupport", "~>3.0.0.beta"
20
- gem.add_dependency "activemodel", "~>3.0.0.beta"
21
- gem.requirements << "`gem install curb` for better HTTP performance"
22
- end
23
- Jeweler::GemcutterTasks.new
24
- rescue LoadError
25
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
2
+ require 'rake/gempackagetask'
3
+
4
+ version = File.read('../VERSION').strip
5
+
6
+ gemspec = Gem::Specification.new do |gem|
7
+ gem.name = "ripple"
8
+ gem.summary = %Q{ripple is an object-mapper library for Riak, the distributed database by Basho.}
9
+ gem.description = %Q{ripple is an object-mapper library for Riak, the distributed database by Basho. It uses ActiveModel to provide an experience that integrates well with Rails 3 applications.}
10
+ gem.version = version
11
+ gem.email = "seancribbs@gmail.com"
12
+ gem.homepage = "http://seancribbs.github.com/ripple"
13
+ gem.authors = ["Sean Cribbs"]
14
+ gem.add_development_dependency "rspec", "~>2.0.0.beta.6"
15
+ gem.add_dependency "riak-client", version
16
+ gem.add_dependency "activesupport", "3.0.0.beta3"
17
+ gem.add_dependency "activemodel", "3.0.0.beta3"
18
+
19
+ files = FileList["**/*"]
20
+ files.exclude /\.DS_Store/
21
+ files.exclude /\#/
22
+ files.exclude /~/
23
+ files.exclude /\.swp/
24
+ files.exclude '**/._*'
25
+ files.exclude '**/*.orig'
26
+ files.exclude '**/*.rej'
27
+ files.exclude /^pkg/
28
+ files.exclude 'ripple.gemspec'
29
+
30
+ gem.files = files.to_a
31
+
32
+ gem.test_files = FileList["spec/**/*.rb"].to_a
26
33
  end
27
34
 
28
- require 'spec/rake/spectask'
29
- Spec::Rake::SpecTask.new(:spec) do |spec|
30
- spec.libs << 'lib' << 'spec'
31
- spec.spec_files = FileList['spec/**/*_spec.rb']
35
+ # Gem packaging tasks
36
+ Rake::GemPackageTask.new(gemspec) do |pkg|
37
+ pkg.need_zip = false
38
+ pkg.need_tar = false
32
39
  end
33
40
 
34
- Spec::Rake::SpecTask.new(:rcov) do |spec|
35
- spec.libs << 'lib' << 'spec'
36
- spec.pattern = 'spec/**/*_spec.rb'
37
- spec.rcov = true
38
- spec.rcov_opts = ['--exclude', 'lib\/spec,bin\/spec,config\/boot.rb,gems,spec_helper']
41
+ task :gem => :gemspec
42
+
43
+ desc %{Build the gemspec file.}
44
+ task :gemspec do
45
+ gemspec.validate
46
+ File.open("#{gemspec.name}.gemspec", 'w'){|f| f.write gemspec.to_ruby }
39
47
  end
40
48
 
41
- task :spec => :check_dependencies
49
+ desc %{Release the gem to RubyGems.org}
50
+ task :release => :gem do
51
+ "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
52
+ end
42
53
 
43
- task :default => :spec
54
+ require 'rspec/core'
55
+ require 'rspec/core/rake_task'
44
56
 
45
- require 'yard'
46
- YARD::Rake::YardocTask.new do |yard|
47
- docfiles = FileList['lib/**/*.rb', 'README*', 'VERSION', 'LICENSE', 'RELEASE_NOTES.textile']
48
- yard.files = docfiles
49
- yard.options = ["--no-private"]
57
+ desc "Run Unit Specs Only"
58
+ Rspec::Core::RakeTask.new(:spec) do |spec|
59
+ spec.pattern = "spec/ripple/**/*_spec.rb"
50
60
  end
51
61
 
52
- task :doc => :yard do
53
- original_dir = Dir.pwd
54
- docs_dir = File.expand_path(File.join(original_dir, "..", "ripple-docs"))
55
- rm_rf File.join(docs_dir, "*")
56
- cp_r File.join(original_dir, "doc", "."), docs_dir
57
- touch File.join(docs_dir, '.nojekyll')
62
+ namespace :spec do
63
+ desc "Run Integration Specs Only"
64
+ Rspec::Core::RakeTask.new(:integration) do |spec|
65
+ spec.pattern = "spec/integration/**/*_spec.rb"
66
+ end
67
+
68
+ desc "Run All Specs"
69
+ Rspec::Core::RakeTask.new(:all) do |spec|
70
+ spec.pattern = "spec/**/*_spec.rb"
71
+ end
58
72
  end
59
73
 
60
- CLOBBER.include(".yardoc")
61
- CLOBBER.include("doc")
74
+ task :default => :spec
@@ -42,9 +42,13 @@ module Ripple
42
42
  Thread.current[:ripple_client] = value
43
43
  end
44
44
 
45
- def config=(value)
45
+ def config=(hash)
46
46
  self.client = nil
47
47
  super
48
48
  end
49
+
50
+ def load_config(config_file)
51
+ self.config = YAML.load_file(File.expand_path config_file).with_indifferent_access[:ripple]
52
+ end
49
53
  end
50
54
  end
@@ -102,6 +102,7 @@ class Time
102
102
  end
103
103
 
104
104
  def self.ripple_cast(value)
105
+ return nil if value.nil?
105
106
  value.respond_to?(:to_time) && value.to_time or raise Ripple::PropertyTypeMismatch.new(self, value)
106
107
  end
107
108
  end
@@ -113,6 +114,7 @@ class Date
113
114
  end
114
115
 
115
116
  def self.ripple_cast(value)
117
+ return nil if value.nil?
116
118
  value.respond_to?(:to_date) && value.to_date or raise Ripple::PropertyTypeMismatch.new(self, value)
117
119
  end
118
120
  end
@@ -124,6 +126,7 @@ class DateTime
124
126
  end
125
127
 
126
128
  def self.ripple_cast(value)
129
+ return nil if value.nil?
127
130
  value.respond_to?(:to_datetime) && value.to_datetime or raise Ripple::PropertyTypeMismatch.new(self, value)
128
131
  end
129
132
  end
@@ -42,8 +42,11 @@ module Ripple
42
42
  extend ActiveSupport::Concern
43
43
  extend ActiveSupport::Autoload
44
44
 
45
+ autoload :Association, "ripple/document/associations"
46
+ autoload :Associations
45
47
  autoload :AttributeMethods
46
48
  autoload :BucketAccess
49
+ autoload :Callbacks
47
50
  autoload :Finders
48
51
  autoload :Persistence
49
52
  autoload :Properties
@@ -53,9 +56,10 @@ module Ripple
53
56
 
54
57
  included do
55
58
  extend BucketAccess
56
- include Persistence
59
+ include Ripple::Document::Persistence
57
60
  include Ripple::EmbeddedDocument
58
- include Finders
61
+ include Ripple::Document::Finders
59
62
  end
63
+
60
64
  end
61
65
  end
@@ -0,0 +1,154 @@
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 Document
18
+ module Associations
19
+ extend ActiveSupport::Concern
20
+ extend ActiveSupport::Autoload
21
+
22
+ autoload :Proxy
23
+ autoload :One
24
+ autoload :Many
25
+ autoload :Embedded
26
+ autoload :Instantiators
27
+ autoload :OneEmbeddedProxy
28
+ autoload :ManyEmbeddedProxy
29
+
30
+ module ClassMethods
31
+ # @private
32
+ def inherited(subclass)
33
+ super
34
+ subclass.associations.merge!(associations)
35
+ end
36
+
37
+ # Associations defined on the document
38
+ def associations
39
+ @associations ||= {}.with_indifferent_access
40
+ end
41
+
42
+ # Creates a singular association
43
+ def one(name, options={})
44
+ create_association(:one, name, options)
45
+ end
46
+
47
+ # Creates a plural association
48
+ def many(name, options={})
49
+ create_association(:many, name, options)
50
+ end
51
+
52
+ private
53
+ def create_association(type, name, options={})
54
+ association = associations[name] = Association.new(type, name, options)
55
+
56
+ define_method(name) do
57
+ get_proxy(association)
58
+ end
59
+
60
+ define_method("#{name}=") do |value|
61
+ get_proxy(association).replace(value)
62
+ value
63
+ end
64
+
65
+ if association.one?
66
+ define_method("#{name}?") do
67
+ get_proxy(association).present?
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ module InstanceMethods
74
+ def associations
75
+ self.class.associations
76
+ end
77
+
78
+ def embedded_associations
79
+ associations.map do |name, association|
80
+ association if association.embeddable?
81
+ end.compact
82
+ end
83
+
84
+ # @private
85
+ def get_proxy(association)
86
+ unless proxy = instance_variable_get(association.ivar)
87
+ proxy = association.proxy_class.new(self, association)
88
+ instance_variable_set(association.ivar, proxy)
89
+ end
90
+ proxy
91
+ end
92
+ end
93
+ end
94
+
95
+ class Association
96
+ attr_reader :type, :name, :options
97
+
98
+ # association options :using, :class_name, :class, :extend,
99
+ # options that may be added :validate
100
+
101
+ def initialize(type, name, options={})
102
+ @type, @name, @options = type, name, options.to_options
103
+ end
104
+
105
+ def class_name
106
+ @class_name ||= case
107
+ when @options[:class_name]
108
+ @options[:class_name]
109
+ when @options[:class]
110
+ @options[:class].to_s
111
+ when many?
112
+ @name.to_s.classify
113
+ else
114
+ @name.to_s.camelize
115
+ end
116
+ end
117
+
118
+ def klass
119
+ @klass ||= options[:class] || class_name.constantize
120
+ end
121
+
122
+ def many?
123
+ @type == :many
124
+ end
125
+
126
+ def one?
127
+ @type == :one
128
+ end
129
+
130
+ def embeddable?
131
+ klass.embeddable?
132
+ end
133
+
134
+ def polymorphic?
135
+ false
136
+ end
137
+
138
+ def ivar
139
+ "@_#{name}"
140
+ end
141
+
142
+ def proxy_class
143
+ return @proxy_class if defined?(@proxy_class)
144
+ proxy_class_name.constantize
145
+ end
146
+
147
+ def proxy_class_name
148
+ @using ||= options[:using] || (embeddable? ? :embedded : :link)
149
+ klass_name = (many? ? 'Many' : 'One') + @using.to_s.camelize + ('Polymorphic' if polymorphic?).to_s + 'Proxy'
150
+ "Ripple::Document::Associations::#{klass_name}"
151
+ end
152
+ end
153
+ end
154
+ end
@@ -15,34 +15,30 @@ require 'ripple'
15
15
 
16
16
  module Ripple
17
17
  module Document
18
- module Persistence
19
- module Callbacks
20
- extend ActiveSupport::Concern
21
-
22
- included do
23
- extend ActiveModel::Callbacks
24
- define_model_callbacks :create, :update, :save, :destroy
18
+ module Associations
19
+ module Embedded
20
+
21
+ def initialize(*args)
22
+ super
23
+ owner.class.validates reflection.name, :associated => true
25
24
  end
26
-
27
- module InstanceMethods
28
- # @private
29
- def save
30
- state = new? ? :create : :update
31
- run_callbacks(:save) do
32
- run_callbacks(state) do
33
- super
34
- end
25
+
26
+ protected
27
+
28
+ def assign_references(docs)
29
+ Array(docs).each do |doc|
30
+ next unless doc.respond_to?(:_parent_document=)
31
+ doc._parent_document = owner
35
32
  end
36
33
  end
37
-
38
- # @private
39
- def destroy
40
- run_callbacks(:destroy) do
41
- super
42
- end
34
+
35
+ def instantiate_target(*args)
36
+ doc = super
37
+ assign_references(doc)
38
+ doc
43
39
  end
44
- end
40
+
45
41
  end
46
42
  end
47
43
  end
48
- end
44
+ end
@@ -0,0 +1,41 @@
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 Document
18
+ module Associations
19
+ module Instantiators
20
+
21
+ def build(attrs={})
22
+ instantiate_target(:new, attrs)
23
+ end
24
+
25
+ def create(attrs={})
26
+ instantiate_target(:create, attrs)
27
+ end
28
+
29
+ def create!(attrs={})
30
+ instantiate_target(:create!, attrs)
31
+ end
32
+
33
+ protected
34
+ def instantiate_target
35
+ raise NotImplementedError
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -11,19 +11,22 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- require 'riak'
14
+ require 'ripple'
15
15
 
16
- module Riak
17
- module Util
18
- module Translation
19
- def i18n_scope
20
- :riak
21
- end
16
+ module Ripple
17
+ module Document
18
+ module Associations
19
+ module Linked
20
+
21
+ def create(attrs={})
22
+ instantiate_target(:create, attrs)
23
+ end
22
24
 
23
- def t(message, options={})
24
- I18n.t("#{i18n_scope}.#{message}", options)
25
+ def create!(attrs={})
26
+ instantiate_target(:create!, attrs)
27
+ end
28
+
25
29
  end
26
30
  end
27
31
  end
28
- end
29
-
32
+ end