gom 0.2.0 → 0.3.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.
- data/README.rdoc +15 -0
- data/Rakefile +1 -1
- data/lib/gom.rb +1 -0
- data/lib/gom/object.rb +15 -19
- data/lib/gom/object/builder.rb +35 -33
- data/lib/gom/object/cached_builder.rb +23 -31
- data/lib/gom/object/collection.rb +49 -57
- data/lib/gom/object/draft.rb +17 -25
- data/lib/gom/object/id.rb +14 -22
- data/lib/gom/object/inspector.rb +46 -54
- data/lib/gom/object/mapping.rb +31 -47
- data/lib/gom/object/proxy.rb +25 -33
- data/lib/gom/spec.rb +11 -0
- data/lib/gom/spec/acceptance/adapter_that_needs_setup.rb +58 -0
- data/lib/gom/spec/acceptance/adapter_with_stateful_storage.rb +19 -21
- data/lib/gom/spec/acceptance/read_only_adapter_with_stateless_storage.rb +9 -8
- data/lib/gom/spec/object.rb +8 -0
- data/lib/gom/storage.rb +30 -26
- data/lib/gom/storage/adapter.rb +26 -43
- data/lib/gom/storage/configuration.rb +75 -68
- data/lib/gom/storage/configuration/view.rb +3 -16
- data/lib/gom/storage/configuration/view/class.rb +5 -22
- data/lib/gom/storage/configuration/view/map_reduce.rb +7 -24
- data/lib/gom/storage/fetcher.rb +24 -32
- data/lib/gom/storage/remover.rb +27 -35
- data/lib/gom/storage/saver.rb +35 -43
- data/spec/acceptance/adapter_spec.rb +16 -4
- data/spec/acceptance/fake_adapter_spec.rb +11 -0
- data/spec/acceptance/object_spec.rb +4 -1
- data/spec/fake_adapter.rb +12 -3
- data/spec/lib/gom/object/builder_spec.rb +5 -5
- data/spec/lib/gom/object/inspector_spec.rb +5 -9
- data/spec/lib/gom/object/mapping_spec.rb +27 -57
- data/spec/lib/gom/storage/adapter_spec.rb +1 -1
- data/spec/lib/gom/storage/configuration_spec.rb +33 -3
- data/spec/lib/gom/storage_spec.rb +19 -0
- metadata +50 -46
@@ -5,20 +5,24 @@ shared_examples_for "a read-only adapter connected to a stateless storage" do
|
|
5
5
|
GOM::Storage.setup
|
6
6
|
end
|
7
7
|
|
8
|
+
after :all do
|
9
|
+
GOM::Storage.teardown
|
10
|
+
end
|
11
|
+
|
8
12
|
describe "fetching an object" do
|
9
13
|
|
10
14
|
it "should return the correct object" do
|
11
15
|
object = GOM::Storage.fetch "test_storage:object_1"
|
12
|
-
object.should be_instance_of(Object)
|
13
|
-
object.
|
16
|
+
object.should be_instance_of(GOM::Spec::Object)
|
17
|
+
object.number.should == 5
|
14
18
|
GOM::Object.id(object).should == "test_storage:object_1"
|
15
19
|
end
|
16
20
|
|
17
21
|
it "should return proxy objects that fetches the related objects" do
|
18
22
|
object = GOM::Storage.fetch "test_storage:object_1"
|
19
|
-
related_object = object.
|
23
|
+
related_object = object.related_object
|
20
24
|
related_object.should be_instance_of(GOM::Object::Proxy)
|
21
|
-
related_object.object.
|
25
|
+
related_object.object.number.should == 7
|
22
26
|
end
|
23
27
|
|
24
28
|
end
|
@@ -58,10 +62,7 @@ shared_examples_for "a read-only adapter connected to a stateless storage" do
|
|
58
62
|
collection = GOM::Storage.collection :test_storage, :test_object_class_view
|
59
63
|
collection.size > 0
|
60
64
|
collection.each do |object_proxy|
|
61
|
-
(
|
62
|
-
object_proxy.object.instance_variable_get(:@number) == 5 ||
|
63
|
-
object_proxy.object.instance_variable_get(:@test) == "test value"
|
64
|
-
).should be_true
|
65
|
+
[ 5, 7 ].should include(object_proxy.object.number)
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
data/lib/gom/storage.rb
CHANGED
@@ -1,39 +1,43 @@
|
|
1
1
|
|
2
|
-
module GOM
|
2
|
+
module GOM::Storage
|
3
3
|
|
4
|
-
|
4
|
+
autoload :Adapter, File.join(File.dirname(__FILE__), "storage", "adapter")
|
5
|
+
autoload :Configuration, File.join(File.dirname(__FILE__), "storage", "configuration")
|
6
|
+
autoload :Fetcher, File.join(File.dirname(__FILE__), "storage", "fetcher")
|
7
|
+
autoload :Remover, File.join(File.dirname(__FILE__), "storage", "remover")
|
8
|
+
autoload :Saver, File.join(File.dirname(__FILE__), "storage", "saver")
|
5
9
|
|
6
|
-
|
7
|
-
|
8
|
-
autoload :Fetcher, File.join(File.dirname(__FILE__), "storage", "fetcher")
|
9
|
-
autoload :Remover, File.join(File.dirname(__FILE__), "storage", "remover")
|
10
|
-
autoload :Saver, File.join(File.dirname(__FILE__), "storage", "saver")
|
10
|
+
# This error can be thrown by the setup method if the given adapter name isn't registered
|
11
|
+
class AdapterNotFoundError < StandardError; end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
# This error can be thrown by an adapter if it's doesn't support write operations
|
14
|
+
class ReadOnlyError < StandardError; end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def self.setup
|
17
|
+
GOM::Object::Mapping.clear!
|
18
|
+
Configuration.setup_all
|
19
|
+
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
21
|
+
def self.teardown
|
22
|
+
Configuration.teardown_all
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
def self.fetch(id_string)
|
26
|
+
id = id_string.is_a?(String) ? GOM::Object::Id.new(id_string) : nil
|
27
|
+
Fetcher.new(id).object
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
30
|
+
def self.store(object, storage_name = nil)
|
31
|
+
Saver.new(object, storage_name).perform
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def self.remove(object_or_id)
|
35
|
+
object_or_id = GOM::Object::Id.new object_or_id if object_or_id.is_a?(String)
|
36
|
+
Remover.new(object_or_id).perform
|
37
|
+
end
|
36
38
|
|
39
|
+
def self.collection(storage_name, *arguments)
|
40
|
+
Configuration[storage_name].adapter.collection *arguments
|
37
41
|
end
|
38
42
|
|
39
43
|
end
|
data/lib/gom/storage/adapter.rb
CHANGED
@@ -1,58 +1,41 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
# Base class for a storage adapter
|
3
|
+
class GOM::Storage::Adapter
|
3
4
|
|
4
|
-
|
5
|
+
# If the adapter is used without a setup, this error is may raised.
|
6
|
+
class NoSetupError < StandardError; end
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
+
# If a view could not be found, this error is raised.
|
9
|
+
class ViewNotFoundError < StandardError; end
|
8
10
|
|
9
|
-
|
10
|
-
class ViewNotFoundError < StandardError; end
|
11
|
+
attr_reader :configuration
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@configuration = configuration
|
16
|
-
end
|
17
|
-
|
18
|
-
def setup(*arguments)
|
19
|
-
not_implemented "setup"
|
20
|
-
end
|
21
|
-
|
22
|
-
def fetch(*arguments)
|
23
|
-
not_implemented "fetch"
|
24
|
-
end
|
25
|
-
|
26
|
-
def store(*arguments)
|
27
|
-
not_implemented "store"
|
28
|
-
end
|
29
|
-
|
30
|
-
def remove(*arguments)
|
31
|
-
not_implemented "remove"
|
32
|
-
end
|
13
|
+
def initialize(configuration)
|
14
|
+
@configuration = configuration
|
15
|
+
end
|
33
16
|
|
34
|
-
|
35
|
-
not_implemented "collection"
|
36
|
-
end
|
17
|
+
[ :setup, :teardown, :fetch, :store, :remove, :collection ].each do |key|
|
37
18
|
|
38
|
-
|
19
|
+
define_method key do |*arguments|
|
20
|
+
not_implemented key
|
21
|
+
end
|
39
22
|
|
40
|
-
|
41
|
-
raise NotImplementedError, "The adapter has no #{method_name} method implemented"
|
42
|
-
end
|
23
|
+
end
|
43
24
|
|
44
|
-
|
45
|
-
@adapter_classes ||= { }
|
46
|
-
@adapter_classes[id.to_sym] = adapter_class
|
47
|
-
end
|
25
|
+
private
|
48
26
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
27
|
+
def not_implemented(method_name)
|
28
|
+
raise NotImplementedError, "The adapter has no #{method_name} method implemented"
|
29
|
+
end
|
53
30
|
|
54
|
-
|
31
|
+
def self.register(id, adapter_class)
|
32
|
+
@adapter_classes ||= { }
|
33
|
+
@adapter_classes[id.to_sym] = adapter_class
|
34
|
+
end
|
55
35
|
|
36
|
+
def self.[](id)
|
37
|
+
@adapter_classes ||= { }
|
38
|
+
@adapter_classes[id.to_sym]
|
56
39
|
end
|
57
40
|
|
58
41
|
end
|
@@ -1,94 +1,101 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "adapter")
|
2
1
|
require 'yaml'
|
3
2
|
|
4
|
-
|
3
|
+
# Stores all information to configure a storage.
|
4
|
+
class GOM::Storage::Configuration
|
5
5
|
|
6
|
-
|
6
|
+
autoload :View, File.join(File.dirname(__FILE__), "configuration", "view")
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :hash
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def initialize(name, hash)
|
12
|
+
@name, @hash = name, { }
|
13
|
+
hash.each{ |key, value| @hash[key.to_sym] = value }
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
16
|
+
def setup
|
17
|
+
adapter.setup
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def teardown
|
21
|
+
adapter.teardown
|
22
|
+
clear_adapter
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
def adapter
|
26
|
+
@adapter ||= adapter_class.new self
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def adapter_class
|
30
|
+
@adapter_class ||= GOM::Storage::Adapter[@hash[:adapter]] || raise(GOM::Storage::AdapterNotFoundError)
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
def [](key)
|
34
|
+
@hash[key.to_sym]
|
35
|
+
end
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
def values_at(*arguments)
|
38
|
+
arguments.map{ |argument| self[argument] }
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
result
|
47
|
-
end
|
41
|
+
def views
|
42
|
+
@views ||= begin
|
43
|
+
result = { }
|
44
|
+
(self["views"] || { }).each do |name, hash|
|
45
|
+
result[name.to_sym] = self.class.view hash
|
48
46
|
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
def self.view(hash)
|
53
|
-
type = hash["type"]
|
54
|
-
method_name = :"#{type}_view"
|
55
|
-
raise NotImplementedError, "the view type '#{type}' doesn't exists" unless self.respond_to?(method_name)
|
56
|
-
self.send method_name, hash
|
57
|
-
end
|
51
|
+
private
|
58
52
|
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
def clear_adapter
|
54
|
+
@adapter, @adapter_class = nil, nil
|
55
|
+
end
|
62
56
|
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
def self.view(hash)
|
58
|
+
type = hash["type"]
|
59
|
+
method_name = :"#{type}_view"
|
60
|
+
raise NotImplementedError, "the view type '#{type}' doesn't exists" unless self.respond_to?(method_name)
|
61
|
+
self.send method_name, hash
|
62
|
+
end
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@configurations[name.to_sym] = self.new name, values
|
71
|
-
end
|
72
|
-
end
|
64
|
+
def self.class_view(hash)
|
65
|
+
View::Class.new hash["class"]
|
66
|
+
end
|
73
67
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
78
|
-
end
|
68
|
+
def self.map_reduce_view(hash)
|
69
|
+
View::MapReduce.new *hash.values_at("map", "reduce")
|
70
|
+
end
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
72
|
+
def self.read(file_name)
|
73
|
+
@configurations = { }
|
74
|
+
YAML::load_file(file_name).each do |name, values|
|
75
|
+
@configurations[name.to_sym] = self.new name, values
|
76
|
+
end
|
77
|
+
end
|
84
78
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
79
|
+
def self.setup_all
|
80
|
+
@configurations.values.each do |configuration|
|
81
|
+
configuration.setup
|
82
|
+
end
|
83
|
+
end
|
89
84
|
|
85
|
+
def self.teardown_all
|
86
|
+
@configurations.values.each do |configuration|
|
87
|
+
configuration.teardown
|
90
88
|
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.[](name)
|
92
|
+
@configurations ||= { }
|
93
|
+
@configurations[name.to_sym]
|
94
|
+
end
|
91
95
|
|
96
|
+
def self.default
|
97
|
+
@configurations ||= { }
|
98
|
+
@configurations.values.first || raise(StandardError, "No storage configuration loaded!")
|
92
99
|
end
|
93
100
|
|
94
101
|
end
|
@@ -1,20 +1,7 @@
|
|
1
1
|
|
2
|
-
module GOM
|
2
|
+
module GOM::Storage::Configuration::View
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# Stores all information to configure a storage.
|
7
|
-
class Configuration
|
8
|
-
|
9
|
-
module View
|
10
|
-
|
11
|
-
autoload :Class, File.join(File.dirname(__FILE__), "view", "class")
|
12
|
-
autoload :MapReduce, File.join(File.dirname(__FILE__), "view", "map_reduce")
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
4
|
+
autoload :Class, File.join(File.dirname(__FILE__), "view", "class")
|
5
|
+
autoload :MapReduce, File.join(File.dirname(__FILE__), "view", "map_reduce")
|
19
6
|
|
20
7
|
end
|
@@ -1,28 +1,11 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
# Contains all the parameters for a class view.
|
3
|
+
class GOM::Storage::Configuration::View::Class
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
# Stores all information to configure a storage.
|
7
|
-
class Configuration
|
8
|
-
|
9
|
-
module View
|
10
|
-
|
11
|
-
# Contains all the parameters for a class view.
|
12
|
-
class Class
|
13
|
-
|
14
|
-
attr_accessor :class_name
|
15
|
-
|
16
|
-
def initialize(class_name)
|
17
|
-
@class_name = class_name
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
5
|
+
attr_accessor :class_name
|
25
6
|
|
7
|
+
def initialize(class_name)
|
8
|
+
@class_name = class_name
|
26
9
|
end
|
27
10
|
|
28
11
|
end
|
@@ -1,29 +1,12 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
# Contains all parameters for a map reduce view.
|
3
|
+
class GOM::Storage::Configuration::View::MapReduce
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
# Stores all information to configure a storage.
|
7
|
-
class Configuration
|
8
|
-
|
9
|
-
module View
|
10
|
-
|
11
|
-
# Contains all parameters for a map reduce view.
|
12
|
-
class MapReduce
|
13
|
-
|
14
|
-
attr_accessor :map
|
15
|
-
attr_accessor :reduce
|
16
|
-
|
17
|
-
def initialize(map, reduce)
|
18
|
-
@map, @reduce = map, reduce
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
5
|
+
attr_accessor :map
|
6
|
+
attr_accessor :reduce
|
26
7
|
|
8
|
+
def initialize(map, reduce)
|
9
|
+
@map, @reduce = map, reduce
|
27
10
|
end
|
28
11
|
|
29
|
-
end
|
12
|
+
end
|