gom 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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