gom 0.1.0 → 0.2.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 +70 -0
- data/lib/gom/object.rb +4 -1
- data/lib/gom/object/builder.rb +47 -0
- data/lib/gom/object/cached_builder.rb +42 -0
- data/lib/gom/object/collection.rb +72 -0
- data/lib/gom/object/draft.rb +34 -0
- data/lib/gom/object/inspector.rb +29 -15
- data/lib/gom/spec/acceptance/adapter_with_stateful_storage.rb +74 -5
- data/lib/gom/spec/acceptance/read_only_adapter_with_stateless_storage.rb +20 -0
- data/lib/gom/storage.rb +6 -2
- data/lib/gom/storage/adapter.rb +11 -4
- data/lib/gom/storage/configuration.rb +30 -1
- data/lib/gom/storage/configuration/view.rb +20 -0
- data/lib/gom/storage/configuration/view/class.rb +28 -0
- data/lib/gom/storage/configuration/view/map_reduce.rb +29 -0
- data/lib/gom/storage/fetcher.rb +9 -34
- data/lib/gom/storage/saver.rb +5 -7
- data/spec/acceptance/object_spec.rb +1 -0
- data/spec/fake_adapter.rb +55 -10
- data/spec/lib/gom/object/builder_spec.rb +51 -0
- data/spec/lib/gom/object/cached_builder_spec.rb +43 -0
- data/spec/lib/gom/object/collection_spec.rb +158 -0
- data/spec/lib/gom/object/draft_spec.rb +59 -0
- data/spec/lib/gom/object/inspector_spec.rb +8 -10
- data/spec/lib/gom/storage/adapter_spec.rb +7 -33
- data/spec/lib/gom/storage/configuration/view/class_spec.rb +17 -0
- data/spec/lib/gom/storage/configuration/view/map_reduce_spec.rb +21 -0
- data/spec/lib/gom/storage/configuration_spec.rb +29 -0
- data/spec/lib/gom/storage/fetcher_spec.rb +7 -38
- data/spec/lib/gom/storage/remover_spec.rb +7 -9
- data/spec/lib/gom/storage/saver_spec.rb +17 -33
- data/spec/lib/gom/storage_spec.rb +33 -9
- data/spec/storage.configuration +10 -0
- metadata +22 -6
- data/lib/gom/object/injector.rb +0 -45
- data/spec/lib/gom/object/injector_spec.rb +0 -51
@@ -47,4 +47,24 @@ shared_examples_for "a read-only adapter connected to a stateless storage" do
|
|
47
47
|
|
48
48
|
end
|
49
49
|
|
50
|
+
describe "fetching a class collection" do
|
51
|
+
|
52
|
+
it "should return a collection" do
|
53
|
+
collection = GOM::Storage.collection :test_storage, :test_object_class_view
|
54
|
+
collection.should be_instance_of(GOM::Object::Collection)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return a collection that contains all object of class Object" do
|
58
|
+
collection = GOM::Storage.collection :test_storage, :test_object_class_view
|
59
|
+
collection.size > 0
|
60
|
+
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
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
50
70
|
end
|
data/lib/gom/storage.rb
CHANGED
@@ -3,11 +3,11 @@ module GOM
|
|
3
3
|
|
4
4
|
module Storage
|
5
5
|
|
6
|
-
autoload :Configuration, File.join(File.dirname(__FILE__), "storage", "configuration")
|
7
6
|
autoload :Adapter, File.join(File.dirname(__FILE__), "storage", "adapter")
|
7
|
+
autoload :Configuration, File.join(File.dirname(__FILE__), "storage", "configuration")
|
8
8
|
autoload :Fetcher, File.join(File.dirname(__FILE__), "storage", "fetcher")
|
9
|
-
autoload :Saver, File.join(File.dirname(__FILE__), "storage", "saver")
|
10
9
|
autoload :Remover, File.join(File.dirname(__FILE__), "storage", "remover")
|
10
|
+
autoload :Saver, File.join(File.dirname(__FILE__), "storage", "saver")
|
11
11
|
|
12
12
|
# This error can be thrown by an adapter if it's doesn't support write operations
|
13
13
|
class ReadOnlyError < StandardError; end
|
@@ -30,6 +30,10 @@ module GOM
|
|
30
30
|
Remover.new(object_or_id).perform
|
31
31
|
end
|
32
32
|
|
33
|
+
def self.collection(storage_name, *arguments)
|
34
|
+
Configuration[storage_name].adapter.collection *arguments
|
35
|
+
end
|
36
|
+
|
33
37
|
end
|
34
38
|
|
35
39
|
end
|
data/lib/gom/storage/adapter.rb
CHANGED
@@ -6,28 +6,35 @@ module GOM
|
|
6
6
|
# Base class for a storage adapter
|
7
7
|
class Adapter
|
8
8
|
|
9
|
+
# If a view could not be found, this error is raised.
|
10
|
+
class ViewNotFoundError < StandardError; end
|
11
|
+
|
9
12
|
attr_reader :configuration
|
10
13
|
|
11
14
|
def initialize(configuration)
|
12
15
|
@configuration = configuration
|
13
16
|
end
|
14
17
|
|
15
|
-
def setup
|
18
|
+
def setup(*arguments)
|
16
19
|
not_implemented "setup"
|
17
20
|
end
|
18
21
|
|
19
|
-
def fetch
|
22
|
+
def fetch(*arguments)
|
20
23
|
not_implemented "fetch"
|
21
24
|
end
|
22
25
|
|
23
|
-
def store
|
26
|
+
def store(*arguments)
|
24
27
|
not_implemented "store"
|
25
28
|
end
|
26
29
|
|
27
|
-
def remove
|
30
|
+
def remove(*arguments)
|
28
31
|
not_implemented "remove"
|
29
32
|
end
|
30
33
|
|
34
|
+
def collection(*arguments)
|
35
|
+
not_implemented "collection"
|
36
|
+
end
|
37
|
+
|
31
38
|
private
|
32
39
|
|
33
40
|
def not_implemented(method_name)
|
@@ -5,9 +5,11 @@ module GOM
|
|
5
5
|
|
6
6
|
module Storage
|
7
7
|
|
8
|
-
# Stores all information to configure a storage
|
8
|
+
# Stores all information to configure a storage.
|
9
9
|
class Configuration
|
10
10
|
|
11
|
+
autoload :View, File.join(File.dirname(__FILE__), "configuration", "view")
|
12
|
+
|
11
13
|
attr_reader :name
|
12
14
|
|
13
15
|
def initialize(name, hash)
|
@@ -35,6 +37,33 @@ module GOM
|
|
35
37
|
arguments.map{ |argument| self[argument] }
|
36
38
|
end
|
37
39
|
|
40
|
+
def views
|
41
|
+
@views ||= begin
|
42
|
+
result = { }
|
43
|
+
(self["views"] || { }).each do |name, hash|
|
44
|
+
result[name.to_sym] = self.class.view hash
|
45
|
+
end
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
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
|
58
|
+
|
59
|
+
def self.class_view(hash)
|
60
|
+
View::Class.new hash["class"]
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.map_reduce_view(hash)
|
64
|
+
View::MapReduce.new *hash.values_at("map", "reduce")
|
65
|
+
end
|
66
|
+
|
38
67
|
def self.read(file_name)
|
39
68
|
@configurations = { }
|
40
69
|
YAML::load_file(file_name).each do |name, values|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module GOM
|
3
|
+
|
4
|
+
module Storage
|
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
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
module GOM
|
3
|
+
|
4
|
+
module Storage
|
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
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module GOM
|
3
|
+
|
4
|
+
module Storage
|
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
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/gom/storage/fetcher.rb
CHANGED
@@ -13,55 +13,30 @@ module GOM
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def object
|
16
|
-
|
16
|
+
fetch_draft
|
17
|
+
return unless has_draft?
|
18
|
+
build_object
|
17
19
|
@object
|
18
20
|
end
|
19
21
|
|
20
22
|
private
|
21
23
|
|
22
|
-
def
|
23
|
-
|
24
|
-
return unless has_object_hash?
|
25
|
-
initialize_object
|
26
|
-
inject_object_hash
|
27
|
-
set_mapping
|
24
|
+
def fetch_draft
|
25
|
+
@draft = @id ? adapter.fetch(@id.object_id) : nil
|
28
26
|
end
|
29
27
|
|
30
|
-
def
|
31
|
-
|
28
|
+
def has_draft?
|
29
|
+
!!@draft
|
32
30
|
end
|
33
31
|
|
34
|
-
def
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def initialize_object
|
39
|
-
@object = GOM::Object::Mapping.object_by_id @id
|
40
|
-
unless @object
|
41
|
-
klass = object_class
|
42
|
-
arity = [ klass.method(:new).arity, 0 ].max
|
43
|
-
@object = klass.new *([ nil ] * arity)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def inject_object_hash
|
48
|
-
injector = GOM::Object::Injector.new @object, @object_hash
|
49
|
-
injector.perform
|
50
|
-
@object = injector.object
|
51
|
-
end
|
52
|
-
|
53
|
-
def set_mapping
|
54
|
-
GOM::Object::Mapping.put @object, @id
|
32
|
+
def build_object
|
33
|
+
@object = GOM::Object::CachedBuilder.new(@draft, @id).object
|
55
34
|
end
|
56
35
|
|
57
36
|
def adapter
|
58
37
|
@adapter ||= GOM::Storage::Configuration[@id.storage_name].adapter
|
59
38
|
end
|
60
39
|
|
61
|
-
def object_class
|
62
|
-
Object.const_get @object_hash[:class]
|
63
|
-
end
|
64
|
-
|
65
40
|
end
|
66
41
|
|
67
42
|
end
|
data/lib/gom/storage/saver.rb
CHANGED
@@ -17,7 +17,7 @@ module GOM
|
|
17
17
|
fetch_id
|
18
18
|
update_storage_name
|
19
19
|
inspect_object
|
20
|
-
|
20
|
+
store_draft
|
21
21
|
store_id
|
22
22
|
end
|
23
23
|
|
@@ -33,14 +33,12 @@ module GOM
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def inspect_object
|
36
|
-
|
37
|
-
|
38
|
-
@object_hash = inspector.object_hash
|
39
|
-
@object_hash[:id] = @id.object_id if @id
|
36
|
+
@draft = GOM::Object::Inspector.new(@object).draft
|
37
|
+
@draft.id = @id.object_id if @id
|
40
38
|
end
|
41
39
|
|
42
|
-
def
|
43
|
-
object_id = adapter.store @
|
40
|
+
def store_draft
|
41
|
+
object_id = adapter.store @draft
|
44
42
|
@id = GOM::Object::Id.new @storage_name.to_s, object_id
|
45
43
|
end
|
46
44
|
|
data/spec/fake_adapter.rb
CHANGED
@@ -1,35 +1,80 @@
|
|
1
1
|
|
2
2
|
class FakeAdapter < GOM::Storage::Adapter
|
3
3
|
|
4
|
-
|
4
|
+
class ClassCollectionFetcher
|
5
5
|
|
6
|
-
|
6
|
+
def initialize(store, storage_name, class_name)
|
7
|
+
@store, @storage_name, @class_name = store, storage_name, class_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def drafts
|
11
|
+
drafts = [ ]
|
12
|
+
@store.each do |object_id, draft|
|
13
|
+
drafts << draft if draft.class_name == @class_name
|
14
|
+
end
|
15
|
+
drafts
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class MapReduceCollectionFetcher
|
21
|
+
|
22
|
+
def initialize(store, storage_name, key, value)
|
23
|
+
@store, @storage_name, @key, @value = store, storage_name, key, value
|
24
|
+
end
|
25
|
+
|
26
|
+
def drafts
|
27
|
+
drafts = [ ]
|
28
|
+
@store.each do |object_id, draft|
|
29
|
+
drafts << draft if draft.properties[@key] == @value
|
30
|
+
end
|
31
|
+
drafts
|
32
|
+
end
|
7
33
|
|
8
34
|
end
|
9
35
|
|
36
|
+
def setup
|
37
|
+
@store = { }
|
38
|
+
end
|
39
|
+
|
10
40
|
def fetch(id)
|
11
|
-
|
41
|
+
@store[id]
|
12
42
|
end
|
13
43
|
|
14
|
-
def store(
|
44
|
+
def store(draft)
|
15
45
|
# store relations
|
16
|
-
|
46
|
+
draft.relations.each do |key, related_object_proxy|
|
17
47
|
GOM::Storage.store related_object_proxy.object, configuration.name
|
18
48
|
id = GOM::Object::Mapping.id_by_object related_object_proxy.object
|
19
|
-
|
49
|
+
draft.relations[key] = GOM::Object::Proxy.new id
|
20
50
|
end
|
21
51
|
|
22
52
|
# may generate an id
|
23
|
-
object_id =
|
53
|
+
object_id = draft.id || next_id
|
24
54
|
|
25
|
-
# store the
|
26
|
-
|
55
|
+
# store the draft
|
56
|
+
@store[object_id] = draft
|
27
57
|
|
28
58
|
object_id
|
29
59
|
end
|
30
60
|
|
31
61
|
def remove(id)
|
32
|
-
|
62
|
+
@store.delete id
|
63
|
+
end
|
64
|
+
|
65
|
+
def collection(view_name)
|
66
|
+
case view_name.to_sym
|
67
|
+
when :test_object_class_view
|
68
|
+
GOM::Object::Collection.new ClassCollectionFetcher.new(@store, configuration.name, "Object")
|
69
|
+
when :test_map_view
|
70
|
+
GOM::Object::Collection.new MapReduceCollectionFetcher.new(@store, configuration.name, :number, 11)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def next_id
|
77
|
+
"object_#{@store.size + 1}"
|
33
78
|
end
|
34
79
|
|
35
80
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
|
2
|
+
|
3
|
+
describe GOM::Object::Builder do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@related_object_proxy = Object.new
|
7
|
+
|
8
|
+
@draft = GOM::Object::Draft.new nil, "Object", { :test => "test value" }, { :related_object => @related_object_proxy }
|
9
|
+
@builder = described_class.new @draft
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "object" do
|
13
|
+
|
14
|
+
it "should initialize an object of the right class" do
|
15
|
+
object = @builder.object
|
16
|
+
object.class.should == Object
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not initialize an object if one is given" do
|
20
|
+
object = Object.new
|
21
|
+
@builder.object = object
|
22
|
+
@builder.object.should === object
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should set the properties" do
|
26
|
+
object = @builder.object
|
27
|
+
object.instance_variable_get(:@test).should == "test value"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should set the relations" do
|
31
|
+
object = @builder.object
|
32
|
+
object.instance_variable_get(:@related_object).should == @related_object_proxy
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should work without a properties hash" do
|
36
|
+
@draft.properties = nil
|
37
|
+
lambda do
|
38
|
+
@builder.object
|
39
|
+
end.should_not raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should work without a relations hash" do
|
43
|
+
@draft.relations = nil
|
44
|
+
lambda do
|
45
|
+
@builder.object
|
46
|
+
end.should_not raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|