ripple 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/LICENSE +13 -0
- data/README.textile +126 -0
- data/RELEASE_NOTES.textile +24 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/lib/riak.rb +45 -0
- data/lib/riak/bucket.rb +105 -0
- data/lib/riak/client.rb +138 -0
- data/lib/riak/client/curb_backend.rb +63 -0
- data/lib/riak/client/http_backend.rb +209 -0
- data/lib/riak/client/net_http_backend.rb +49 -0
- data/lib/riak/failed_request.rb +37 -0
- data/lib/riak/i18n.rb +15 -0
- data/lib/riak/invalid_response.rb +25 -0
- data/lib/riak/link.rb +54 -0
- data/lib/riak/locale/en.yml +37 -0
- data/lib/riak/map_reduce.rb +240 -0
- data/lib/riak/map_reduce_error.rb +20 -0
- data/lib/riak/robject.rb +234 -0
- data/lib/riak/util/headers.rb +44 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/translation.rb +29 -0
- data/lib/riak/walk_spec.rb +113 -0
- data/lib/ripple.rb +48 -0
- data/lib/ripple/core_ext/casting.rb +96 -0
- data/lib/ripple/document.rb +60 -0
- data/lib/ripple/document/attribute_methods.rb +111 -0
- data/lib/ripple/document/attribute_methods/dirty.rb +52 -0
- data/lib/ripple/document/attribute_methods/query.rb +49 -0
- data/lib/ripple/document/attribute_methods/read.rb +38 -0
- data/lib/ripple/document/attribute_methods/write.rb +36 -0
- data/lib/ripple/document/bucket_access.rb +38 -0
- data/lib/ripple/document/finders.rb +84 -0
- data/lib/ripple/document/persistence.rb +93 -0
- data/lib/ripple/document/persistence/callbacks.rb +48 -0
- data/lib/ripple/document/properties.rb +85 -0
- data/lib/ripple/document/validations.rb +44 -0
- data/lib/ripple/embedded_document.rb +38 -0
- data/lib/ripple/embedded_document/persistence.rb +46 -0
- data/lib/ripple/i18n.rb +15 -0
- data/lib/ripple/locale/en.yml +16 -0
- data/lib/ripple/property_type_mismatch.rb +23 -0
- data/lib/ripple/translation.rb +24 -0
- data/ripple.gemspec +159 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/riak/bucket_spec.rb +141 -0
- data/spec/riak/client_spec.rb +169 -0
- data/spec/riak/curb_backend_spec.rb +50 -0
- data/spec/riak/headers_spec.rb +34 -0
- data/spec/riak/http_backend_spec.rb +136 -0
- data/spec/riak/link_spec.rb +50 -0
- data/spec/riak/map_reduce_spec.rb +347 -0
- data/spec/riak/multipart_spec.rb +36 -0
- data/spec/riak/net_http_backend_spec.rb +28 -0
- data/spec/riak/object_spec.rb +444 -0
- data/spec/riak/walk_spec_spec.rb +208 -0
- data/spec/ripple/attribute_methods_spec.rb +149 -0
- data/spec/ripple/bucket_access_spec.rb +48 -0
- data/spec/ripple/callbacks_spec.rb +86 -0
- data/spec/ripple/document_spec.rb +35 -0
- data/spec/ripple/embedded_document_spec.rb +52 -0
- data/spec/ripple/finders_spec.rb +146 -0
- data/spec/ripple/persistence_spec.rb +89 -0
- data/spec/ripple/properties_spec.rb +195 -0
- data/spec/ripple/ripple_spec.rb +43 -0
- data/spec/ripple/validations_spec.rb +64 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/http_backend_implementation_examples.rb +215 -0
- data/spec/support/mock_server.rb +58 -0
- metadata +221 -0
@@ -0,0 +1,44 @@
|
|
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 'riak'
|
15
|
+
|
16
|
+
module Riak
|
17
|
+
module Util
|
18
|
+
# Represents headers from an HTTP response
|
19
|
+
class Headers
|
20
|
+
include Net::HTTPHeader
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
initialize_http_header({})
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parse a single header line into its key and value
|
27
|
+
# @param [String] chunk a single header line
|
28
|
+
def self.parse(chunk)
|
29
|
+
line = chunk.strip
|
30
|
+
# thanks Net::HTTPResponse
|
31
|
+
return [nil,nil] if chunk =~ /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in
|
32
|
+
m = /\A([^:]+):\s*/.match(line)
|
33
|
+
[m[1], m.post_match] rescue [nil, nil]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Parses a header line and adds it to the header collection
|
37
|
+
# @param [String] chunk a single header line
|
38
|
+
def parse(chunk)
|
39
|
+
key, value = self.class.parse(chunk)
|
40
|
+
add_field(key, value) if key && value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'riak'
|
15
|
+
|
16
|
+
module Riak
|
17
|
+
module Util
|
18
|
+
# Utility methods for handling multipart/mixed responses
|
19
|
+
module Multipart
|
20
|
+
extend self
|
21
|
+
# Parses a multipart/mixed body into its constituent parts, including nested multipart/mixed sections
|
22
|
+
# @param [String] data the multipart body data
|
23
|
+
# @param [String] boundary the boundary string given in the Content-Type header
|
24
|
+
def parse(data, boundary)
|
25
|
+
contents = data.match(/\n--#{Regexp.escape(boundary)}--\n/).pre_match rescue ""
|
26
|
+
contents.split(/\n--#{Regexp.escape(boundary)}\n/).reject(&:blank?).map do |part|
|
27
|
+
headers = Headers.new
|
28
|
+
if md = part.match(/\r?\n\r?\n/)
|
29
|
+
body = md.post_match
|
30
|
+
md.pre_match.split(/\r?\n/).each do |line|
|
31
|
+
headers.parse(line)
|
32
|
+
end
|
33
|
+
|
34
|
+
if headers["content-type"] =~ /multipart\/mixed/
|
35
|
+
boundary = extract_boundary(headers.to_hash["content-type"].first)
|
36
|
+
parse(body, boundary)
|
37
|
+
else
|
38
|
+
{:headers => headers.to_hash, :body => body}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
# Extracts the boundary string from a Content-Type header that is a multipart type
|
45
|
+
# @param [String] header_string the Content-Type header
|
46
|
+
# @return [String] the boundary string separating each part
|
47
|
+
def extract_boundary(header_string)
|
48
|
+
$1 if header_string =~ /boundary=([A-Za-z0-9\'()+_,-.\/:=?]+)/
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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 'riak'
|
15
|
+
|
16
|
+
module Riak
|
17
|
+
module Util
|
18
|
+
module Translation
|
19
|
+
def i18n_scope
|
20
|
+
:riak
|
21
|
+
end
|
22
|
+
|
23
|
+
def t(message, options={})
|
24
|
+
I18n.t("#{i18n_scope}.#{message}", options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,113 @@
|
|
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 'riak'
|
15
|
+
|
16
|
+
module Riak
|
17
|
+
|
18
|
+
# The specification of how to follow links from one object to another in Riak,
|
19
|
+
# when using the link-walker resource.
|
20
|
+
# Example link-walking operation:
|
21
|
+
# GET /raw/artists/REM/albums,_,_/tracks,_,1
|
22
|
+
# This operation would have two WalkSpecs:
|
23
|
+
# Riak::WalkSpec.new({:bucket => 'albums'})
|
24
|
+
# Riak::WalkSpec.new({:bucket => 'tracks', :result => true})
|
25
|
+
class WalkSpec
|
26
|
+
include Util::Translation
|
27
|
+
# @return [String] The bucket followed links should be restricted to. "_" represents all buckets.
|
28
|
+
attr_accessor :bucket
|
29
|
+
|
30
|
+
# @return [String] The "riaktag" or "rel" that followed links should be restricted to. "_" represents all tags.
|
31
|
+
attr_accessor :tag
|
32
|
+
|
33
|
+
# @return [Boolean] Whether objects should be returned from this phase of link walking. Default is false.
|
34
|
+
attr_accessor :keep
|
35
|
+
|
36
|
+
# Normalize a list of walk specs into WalkSpec objects.
|
37
|
+
def self.normalize(*params)
|
38
|
+
params.flatten!
|
39
|
+
specs = []
|
40
|
+
while params.length > 0
|
41
|
+
param = params.shift
|
42
|
+
case param
|
43
|
+
when Hash
|
44
|
+
specs << new(param)
|
45
|
+
when WalkSpec
|
46
|
+
specs << param
|
47
|
+
else
|
48
|
+
if params.length >= 2
|
49
|
+
specs << new(param, params.shift, params.shift)
|
50
|
+
else
|
51
|
+
raise ArgumentError, t("too_few_arguments", :params => params.inspect)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
specs
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates a walk-spec for use in finding other objects in Riak.
|
59
|
+
# @overload initialize(hash)
|
60
|
+
# Creates a walk-spec from a hash.
|
61
|
+
# @param [Hash] hash options for the walk-spec
|
62
|
+
# @option hash [String] :bucket ("_") the bucket the links should point to (default '_' is all)
|
63
|
+
# @option hash [String] :tag ("_") the tag to filter links by (default '_' is all)
|
64
|
+
# @option hash [Boolean] :keep (false) whether to return results from following this link specification
|
65
|
+
# @overload initialize(bucket, tag, keep)
|
66
|
+
# Creates a walk-spec from a bucket-tag-result triple.
|
67
|
+
# @param [String] bucket the bucket the links should point to (default '_' is all)
|
68
|
+
# @param [String] tag the tag to filter links by (default '_' is all)
|
69
|
+
# @param [Boolean] keep whether to return results from following this link specification
|
70
|
+
# @see {Riak::RObject#walk}
|
71
|
+
def initialize(*args)
|
72
|
+
args.flatten!
|
73
|
+
case args.size
|
74
|
+
when 1
|
75
|
+
hash = args.first
|
76
|
+
raise ArgumentError, t("hash_type", :hash => hash.inspect) unless Hash === hash
|
77
|
+
assign(hash[:bucket], hash[:tag], hash[:keep])
|
78
|
+
when 3
|
79
|
+
assign(*args)
|
80
|
+
else
|
81
|
+
raise ArgumentError, t("wrong_argument_count_walk_spec")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Converts the walk-spec into the form required by the link-walker resource URL
|
86
|
+
def to_s
|
87
|
+
"#{@bucket || '_'},#{@tag || '_'},#{@keep ? '1' : '_'}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def ==(other)
|
91
|
+
other.is_a?(WalkSpec) && other.bucket == bucket && other.tag == tag && other.keep == keep
|
92
|
+
end
|
93
|
+
|
94
|
+
def ===(other)
|
95
|
+
self == other || case other
|
96
|
+
when WalkSpec
|
97
|
+
other.keep == keep &&
|
98
|
+
(bucket == "_" || bucket == other.bucket) &&
|
99
|
+
(tag == "_" || tag == other.tag)
|
100
|
+
when Link
|
101
|
+
(bucket == "_" || bucket == other.url.split("/")[2]) &&
|
102
|
+
(tag == "_" || tag == other.rel)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def assign(bucket, tag, result)
|
108
|
+
@bucket = bucket || "_"
|
109
|
+
@tag = tag || "_"
|
110
|
+
@keep = result || false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/ripple.rb
ADDED
@@ -0,0 +1,48 @@
|
|
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 'riak'
|
16
|
+
require 'active_support/all'
|
17
|
+
require 'active_model'
|
18
|
+
require 'ripple/i18n'
|
19
|
+
|
20
|
+
# Contains the classes and modules related to the ODM built on top of
|
21
|
+
# the basic Riak client.
|
22
|
+
module Ripple
|
23
|
+
extend ActiveSupport::Autoload
|
24
|
+
include ActiveSupport::Configurable
|
25
|
+
|
26
|
+
autoload :EmbeddedDocument
|
27
|
+
autoload :Document
|
28
|
+
autoload :PropertyTypeMismatch
|
29
|
+
autoload :Translation
|
30
|
+
|
31
|
+
class << self
|
32
|
+
# @return [Riak::Client] The client for the current thread.
|
33
|
+
def client
|
34
|
+
Thread.current[:ripple_client] ||= Riak::Client.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets the client for the current thread.
|
38
|
+
# @param [Riak::Client] value the client
|
39
|
+
def client=(value)
|
40
|
+
Thread.current[:ripple_client] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def config=(value)
|
44
|
+
self.client = nil
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
+
# @private
|
16
|
+
class Object
|
17
|
+
def self.ripple_cast(value)
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
class Symbol
|
24
|
+
def self.ripple_cast(value)
|
25
|
+
return nil if value.nil?
|
26
|
+
value.respond_to?(:to_s) && value.to_s.intern or raise Ripple::PropertyTypeMismatch.new(self, value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
class Numeric
|
32
|
+
def self.ripple_cast(value)
|
33
|
+
return nil if value.nil?
|
34
|
+
raise Ripple::PropertyTypeMismatch.new(self,value) unless value.respond_to?(:to_i) && value.respond_to?(:to_f)
|
35
|
+
float_value = value.to_f
|
36
|
+
int_value = value.to_i
|
37
|
+
float_value == int_value ? int_value : float_value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @private
|
42
|
+
class Integer
|
43
|
+
def self.ripple_cast(value)
|
44
|
+
return nil if value.nil?
|
45
|
+
value.respond_to?(:to_i) && value.to_i or raise Ripple::PropertyTypeMismatch.new(self, value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @private
|
50
|
+
class Float
|
51
|
+
def self.ripple_cast(value)
|
52
|
+
return nil if value.nil?
|
53
|
+
value.respond_to?(:to_f) && value.to_f or raise Ripple::PropertyTypeMismatch.new(self, value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @private
|
58
|
+
class String
|
59
|
+
def self.ripple_cast(value)
|
60
|
+
value.respond_to?(:to_s) && value.to_s or raise Ripple::PropertyTypeMismatch.new(self, value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Stand-in for true/false property types.
|
65
|
+
module Boolean
|
66
|
+
def self.ripple_cast(value)
|
67
|
+
case value
|
68
|
+
when NilClass
|
69
|
+
nil
|
70
|
+
when Numeric
|
71
|
+
!value.zero?
|
72
|
+
when TrueClass, FalseClass
|
73
|
+
value
|
74
|
+
when /^\s*t/i
|
75
|
+
true
|
76
|
+
when /^\s*f/i
|
77
|
+
false
|
78
|
+
else
|
79
|
+
value.present?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @private
|
85
|
+
class TrueClass
|
86
|
+
def self.ripple_cast(value)
|
87
|
+
Boolean.ripple_cast(value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
class FalseClass
|
93
|
+
def self.ripple_cast(value)
|
94
|
+
Boolean.ripple_cast(value)
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,60 @@
|
|
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
|
+
# Represents a model stored in Riak, serialized in JSON object (document).
|
18
|
+
# Ripple::Document models aim to be fully ActiveModel compatible, with a keen
|
19
|
+
# eye toward features that developers expect from ActiveRecord, DataMapper and MongoMapper.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# class Email
|
24
|
+
# include Ripple::Document
|
25
|
+
# property :from, String, :presence => true
|
26
|
+
# property :to, String, :presence => true
|
27
|
+
# property :sent, Time, :default => proc { Time.now }
|
28
|
+
# property :body, String
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# email = Email.find("37458abc752f8413e") # GET /raw/emails/37458abc752f8413e
|
32
|
+
# email.from = "someone@nowhere.net"
|
33
|
+
# email.save # PUT /raw/emails/37458abc752f8413e
|
34
|
+
#
|
35
|
+
# reply = Email.new
|
36
|
+
# reply.from = "justin@bashoooo.com"
|
37
|
+
# reply.to = "sean@geeemail.com"
|
38
|
+
# reply.body = "Riak is a good fit for scalable Ruby apps."
|
39
|
+
# reply.save # POST /raw/emails (Riak-assigned key)
|
40
|
+
#
|
41
|
+
module Document
|
42
|
+
extend ActiveSupport::Concern
|
43
|
+
extend ActiveSupport::Autoload
|
44
|
+
|
45
|
+
autoload :AttributeMethods
|
46
|
+
autoload :BucketAccess
|
47
|
+
autoload :Finders
|
48
|
+
autoload :Persistence
|
49
|
+
autoload :Properties
|
50
|
+
autoload :Property, "ripple/document/properties"
|
51
|
+
autoload :Validations
|
52
|
+
|
53
|
+
included do
|
54
|
+
extend BucketAccess
|
55
|
+
include Persistence
|
56
|
+
include EmbeddedDocument
|
57
|
+
include Finders
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|