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.
Files changed (36) hide show
  1. data/README.rdoc +70 -0
  2. data/lib/gom/object.rb +4 -1
  3. data/lib/gom/object/builder.rb +47 -0
  4. data/lib/gom/object/cached_builder.rb +42 -0
  5. data/lib/gom/object/collection.rb +72 -0
  6. data/lib/gom/object/draft.rb +34 -0
  7. data/lib/gom/object/inspector.rb +29 -15
  8. data/lib/gom/spec/acceptance/adapter_with_stateful_storage.rb +74 -5
  9. data/lib/gom/spec/acceptance/read_only_adapter_with_stateless_storage.rb +20 -0
  10. data/lib/gom/storage.rb +6 -2
  11. data/lib/gom/storage/adapter.rb +11 -4
  12. data/lib/gom/storage/configuration.rb +30 -1
  13. data/lib/gom/storage/configuration/view.rb +20 -0
  14. data/lib/gom/storage/configuration/view/class.rb +28 -0
  15. data/lib/gom/storage/configuration/view/map_reduce.rb +29 -0
  16. data/lib/gom/storage/fetcher.rb +9 -34
  17. data/lib/gom/storage/saver.rb +5 -7
  18. data/spec/acceptance/object_spec.rb +1 -0
  19. data/spec/fake_adapter.rb +55 -10
  20. data/spec/lib/gom/object/builder_spec.rb +51 -0
  21. data/spec/lib/gom/object/cached_builder_spec.rb +43 -0
  22. data/spec/lib/gom/object/collection_spec.rb +158 -0
  23. data/spec/lib/gom/object/draft_spec.rb +59 -0
  24. data/spec/lib/gom/object/inspector_spec.rb +8 -10
  25. data/spec/lib/gom/storage/adapter_spec.rb +7 -33
  26. data/spec/lib/gom/storage/configuration/view/class_spec.rb +17 -0
  27. data/spec/lib/gom/storage/configuration/view/map_reduce_spec.rb +21 -0
  28. data/spec/lib/gom/storage/configuration_spec.rb +29 -0
  29. data/spec/lib/gom/storage/fetcher_spec.rb +7 -38
  30. data/spec/lib/gom/storage/remover_spec.rb +7 -9
  31. data/spec/lib/gom/storage/saver_spec.rb +17 -33
  32. data/spec/lib/gom/storage_spec.rb +33 -9
  33. data/spec/storage.configuration +10 -0
  34. metadata +22 -6
  35. data/lib/gom/object/injector.rb +0 -45
  36. 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
@@ -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
@@ -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
@@ -13,55 +13,30 @@ module GOM
13
13
  end
14
14
 
15
15
  def object
16
- perform
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 perform
23
- fetch_object_hash
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 fetch_object_hash
31
- @object_hash = @id ? adapter.fetch(@id.object_id) : nil
28
+ def has_draft?
29
+ !!@draft
32
30
  end
33
31
 
34
- def has_object_hash?
35
- !!@object_hash
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
@@ -17,7 +17,7 @@ module GOM
17
17
  fetch_id
18
18
  update_storage_name
19
19
  inspect_object
20
- store_object_hash
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
- inspector = GOM::Object::Inspector.new @object
37
- inspector.perform
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 store_object_hash
43
- object_id = adapter.store @object_hash
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
 
@@ -6,6 +6,7 @@ GOM::Storage::Configuration.read File.join(File.dirname(__FILE__), "..", "storag
6
6
  describe "object" do
7
7
 
8
8
  before :each do
9
+ GOM::Storage.setup
9
10
  @object = Object.new
10
11
  end
11
12
 
@@ -1,35 +1,80 @@
1
1
 
2
2
  class FakeAdapter < GOM::Storage::Adapter
3
3
 
4
- STORE = { }
4
+ class ClassCollectionFetcher
5
5
 
6
- def setup
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
- STORE[id]
41
+ @store[id]
12
42
  end
13
43
 
14
- def store(object_hash)
44
+ def store(draft)
15
45
  # store relations
16
- (object_hash[:relations] || { }).each do |key, related_object_proxy|
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
- object_hash[:relations][key] = GOM::Object::Proxy.new id
49
+ draft.relations[key] = GOM::Object::Proxy.new id
20
50
  end
21
51
 
22
52
  # may generate an id
23
- object_id = object_hash[:id] || "object_#{STORE.size + 1}"
53
+ object_id = draft.id || next_id
24
54
 
25
- # store the object hash
26
- STORE[object_id] = object_hash
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
- STORE.delete id
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