gom-filesystem-adapter 0.1.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Philipp Brüll
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,50 @@
1
+
2
+ = Generic Object Mapper - Filesystem adapter
3
+
4
+ The filesystem adapter for the Generic Object Mapper (http://github.com/phifty/gom) provides an easy way to store
5
+ object data in the filesystem. Currently the adapter is read-only. The object data - stored in YML files - can be
6
+ mapped to object, but no object data can be written to disk.
7
+
8
+ == Configuration
9
+
10
+ If the adapter <tt>filesystem</tt> is chosen in the storage configuration, the following configuration values should
11
+ specified.
12
+
13
+ * <tt>directory</tt> - specifies to directory where the object data is placed in.
14
+
15
+ === Example
16
+
17
+ storage_name:
18
+ adapter: filesystem
19
+ directory: /var/project-name/data
20
+
21
+ == Files
22
+
23
+ The adapter reads all the *.yml files in the specified directory. The basename of the file defines the class of the
24
+ containing objects. A file can store multiple object of that class and is structured the following way.
25
+
26
+ # file Book.yml
27
+ book_1:
28
+ properties:
29
+ pages: 1253
30
+ relations:
31
+ author: author_1
32
+
33
+ # file Author.yml
34
+ author_1:
35
+ properties:
36
+ name: "Mr. Storyteller"
37
+
38
+ A fetch of that book would look like:
39
+
40
+ book = GOM::Storage.fetch "storage_name:book_1"
41
+
42
+ The fetched object would have the instance variable <tt>@pages</tt> set to <tt>1253</tt> and <tt>@author</tt> would
43
+ point to an object of the class <tt>Author</tt> with the id <tt>author_1</tt>.
44
+
45
+ == Development
46
+
47
+ Development has been done test-driven and the code follows at most the Clean Code paradigms. Code smells has been
48
+ removed by using the reek[http://github.com/kevinrutherford/reek] code smell detector.
49
+
50
+ This project is still experimental and under development. Any bug report and contribution is welcome!
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ gem 'rspec'
3
+ gem 'reek'
4
+ require 'rspec'
5
+ require 'rake/rdoctask'
6
+ require 'rspec/core/rake_task'
7
+ require 'reek/rake/task'
8
+
9
+ task :default => :spec
10
+
11
+ namespace :gem do
12
+
13
+ desc "Builds the gem"
14
+ task :build do
15
+ system "gem build *.gemspec && mkdir -p pkg/ && mv *.gem pkg/"
16
+ end
17
+
18
+ desc "Builds and installs the gem"
19
+ task :install => :build do
20
+ system "gem install pkg/"
21
+ end
22
+
23
+ end
24
+
25
+ Reek::Rake::Task.new do |task|
26
+ task.fail_on_error = true
27
+ end
28
+
29
+ desc "Generate the rdoc"
30
+ Rake::RDocTask.new do |rdoc|
31
+ rdoc.rdoc_files.add [ "README.rdoc", "lib/**/*.rb" ]
32
+ rdoc.main = "README.rdoc"
33
+ rdoc.title = ""
34
+ end
35
+
36
+ desc "Run all specs in spec directory"
37
+ RSpec::Core::RakeTask.new do |task|
38
+ task.pattern = "spec/gom/**/*_spec.rb"
39
+ end
40
+
41
+ namespace :spec do
42
+
43
+ desc "Run all integration specs in spec/acceptance directory"
44
+ RSpec::Core::RakeTask.new(:acceptance) do |task|
45
+ task.pattern = "spec/acceptance/**/*_spec.rb"
46
+ end
47
+
48
+ end
data/lib/filesystem.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'gom'
2
+ require File.join(File.dirname(__FILE__), "gom", "storage")
3
+
4
+ GOM::Storage::Adapter.register :filesystem, GOM::Storage::Filesystem::Adapter
@@ -0,0 +1,47 @@
1
+
2
+ module GOM
3
+
4
+ module Storage
5
+
6
+ module Filesystem
7
+
8
+ # The filesystem storage adapter
9
+ class Adapter < GOM::Storage::Adapter
10
+
11
+ def initialize(configuration)
12
+ super configuration
13
+ end
14
+
15
+ def setup
16
+ load_data
17
+ end
18
+
19
+ def fetch(id)
20
+ @data[id]
21
+ end
22
+
23
+ def store(object, storage_name = nil)
24
+ read_only_error "store"
25
+ end
26
+
27
+ def remove(object)
28
+ read_only_error "remove"
29
+ end
30
+
31
+ private
32
+
33
+ def load_data
34
+ @data = GOM::Storage::Filesystem::Loader.new(configuration[:directory]).data
35
+ end
36
+
37
+ def read_only_error(method_name)
38
+ raise GOM::Storage::ReadOnlyError, "The adapter doesn't provide write methods"
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,87 @@
1
+ require 'yaml'
2
+
3
+ module GOM
4
+
5
+ module Storage
6
+
7
+ module Filesystem
8
+
9
+ # The loader for the filesystem data that is provided by the storage adapter.
10
+ class Loader
11
+
12
+ attr_accessor :directory
13
+
14
+ def initialize(directory)
15
+ @directory = directory
16
+ @data = { }
17
+ end
18
+
19
+ def data
20
+ load_yml_files
21
+ @data
22
+ end
23
+
24
+ private
25
+
26
+ def load_yml_files
27
+ @data = { }
28
+ Dir[File.join(@directory, "*.yml")].each do |filename|
29
+ load_yml_file filename
30
+ end
31
+ end
32
+
33
+ def load_yml_file(filename)
34
+ classname = File.basename(filename).sub(/\..*$/, "")
35
+ load_file_hash classname, YAML.load_file(filename)
36
+ end
37
+
38
+ def load_file_hash(classname, file_hash)
39
+ file_hash.each do |id, hash|
40
+ @data[id] = Builder.new(classname, hash).object_hash
41
+ end
42
+ end
43
+
44
+ # Builds an object hash out of the file hashes.
45
+ class Builder
46
+
47
+ attr_reader :object_hash
48
+
49
+ def initialize(classname, hash)
50
+ @classname, @hash = classname, hash
51
+ @object_hash = { }
52
+ copy_classname
53
+ copy_properties
54
+ copy_relations
55
+ end
56
+
57
+ private
58
+
59
+ def copy_classname
60
+ @object_hash[:class] = @classname
61
+ end
62
+
63
+ def copy_properties
64
+ properties = { }
65
+ (@hash["properties"] || { }).each do |key, value|
66
+ properties[key] = value
67
+ end
68
+ @object_hash[:properties] = properties unless properties.empty?
69
+ end
70
+
71
+ def copy_relations
72
+ relations = { }
73
+ (@hash["relations"] || { }).each do |key, value|
74
+ relations[key] = GOM::Object::Proxy.new GOM::Object::Id.new(value)
75
+ end
76
+ @object_hash[:relations] = relations unless relations.empty?
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module GOM
3
+
4
+ module Storage
5
+
6
+ module Filesystem
7
+
8
+ autoload :Adapter, File.join(File.dirname(__FILE__), "filesystem", "adapter")
9
+ autoload :Loader, File.join(File.dirname(__FILE__), "filesystem", "loader")
10
+
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module GOM
3
+
4
+ module Storage
5
+
6
+ autoload :Filesystem, File.join(File.dirname(__FILE__), "storage", "filesystem")
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib", "filesystem"))
3
+
4
+ GOM::Storage::Configuration.read File.join(File.dirname(__FILE__), "..", "storage.configuration")
5
+
6
+ describe "filesystem adapter" do
7
+
8
+ it_should_behave_like "a read-only adapter connected to a stateless storage"
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+
2
+ object_1:
3
+ properties:
4
+ number: 5
5
+ relations:
6
+ related_object: test_storage:object_2
7
+
8
+ object_2:
9
+ properties:
10
+ test: test value
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
2
+
3
+ describe GOM::Storage::Filesystem::Adapter do
4
+
5
+ before :each do
6
+ @data = {
7
+ "object_1" => {
8
+ :class => "Object",
9
+ :properties => { :test => "test value" }
10
+ },
11
+ "object_2" => {
12
+ :class => "Object",
13
+ :properties => { :test => "another test value" }
14
+ }
15
+ }
16
+
17
+ @loader = mock GOM::Storage::Filesystem::Loader, :data => @data
18
+ GOM::Storage::Filesystem::Loader.stub(:new).and_return(@loader)
19
+
20
+ @configuration = mock GOM::Storage::Configuration
21
+ @configuration.stub(:[]).with(:directory).and_return("test_directory")
22
+ @adapter = described_class.new @configuration
23
+ end
24
+
25
+ it "should register the adapter" do
26
+ GOM::Storage::Adapter[:filesystem].should == GOM::Storage::Filesystem::Adapter
27
+ end
28
+
29
+ describe "setup" do
30
+
31
+ it "should initialize a file system loader" do
32
+ GOM::Storage::Filesystem::Loader.should_receive(:new).with("test_directory").and_return(@loader)
33
+ @adapter.setup
34
+ end
35
+
36
+ it "should load the data" do
37
+ @loader.should_receive(:data).and_return(@data)
38
+ @adapter.setup
39
+ end
40
+
41
+ end
42
+
43
+ describe "fetch" do
44
+
45
+ before :each do
46
+ @adapter.setup
47
+ end
48
+
49
+ it "should return the object hash" do
50
+ @adapter.fetch("object_1").should == @data["object_1"]
51
+ end
52
+
53
+ end
54
+
55
+ describe "store" do
56
+
57
+ it "should raise a GOM::Storage::ReadOnlyError" do
58
+ lambda do
59
+ @adapter.store Object.new, "test_storage"
60
+ end.should raise_error(GOM::Storage::ReadOnlyError)
61
+ end
62
+
63
+ end
64
+
65
+ describe "remove" do
66
+
67
+ it "should raise a GOM::Storage::ReadOnlyError" do
68
+ lambda do
69
+ @adapter.remove Object.new
70
+ end.should raise_error(GOM::Storage::ReadOnlyError)
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
2
+
3
+ describe GOM::Storage::Filesystem::Loader do
4
+
5
+ before :each do
6
+ @directory = "directory"
7
+ @loader = GOM::Storage::Filesystem::Loader.new @directory
8
+ end
9
+
10
+ describe "initialize" do
11
+
12
+ it "should set the directory" do
13
+ @loader.directory.should == @directory
14
+ end
15
+
16
+ end
17
+
18
+ describe "data" do
19
+
20
+ before :each do
21
+ @filename = "directory/Object.yml"
22
+ @filenames = [ @filename ]
23
+ Dir.stub(:[]).and_return(@filenames)
24
+
25
+ @proxy = mock GOM::Object::Proxy
26
+ GOM::Object::Proxy.stub(:new).and_return(@proxy)
27
+
28
+ @file_hash = {
29
+ "object_1" => {
30
+ "properties" => {
31
+ "test" => "test value"
32
+ },
33
+ "relations" => {
34
+ "related_object" => "test_storage:object_2"
35
+ }
36
+ },
37
+ "object_2" => {
38
+ "properties" => {
39
+ "test" => "another test value"
40
+ }
41
+ }
42
+ }
43
+ YAML.stub(:load_file).and_return(@file_hash)
44
+ end
45
+
46
+ it "should searches all .yml file in the directory" do
47
+ Dir.should_receive(:[]).with("directory/*.yml").and_return(@filenames)
48
+ @loader.data
49
+ end
50
+
51
+ it "should load the files" do
52
+ YAML.should_receive(:load_file).with(@filename).and_return(@file_hash)
53
+ @loader.data
54
+ end
55
+
56
+ it "should create object proxies for relations" do
57
+ GOM::Object::Proxy.should_receive(:new).with(GOM::Object::Id.new("test_storage:object_2")).and_return(@proxy)
58
+ @loader.data
59
+ end
60
+
61
+ it "should convert the file hash into object hashes" do
62
+ @loader.data.should == {
63
+ "object_1" => {
64
+ :class => "Object",
65
+ :properties => { "test" => "test value" },
66
+ :relations => { "related_object" => @proxy }
67
+ },
68
+ "object_2" => {
69
+ :class => "Object",
70
+ :properties => { "test" => "another test value" }
71
+ }
72
+ }
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>= 2'
3
+ require 'rspec'
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "filesystem"))
6
+ require 'gom/spec'
@@ -0,0 +1,5 @@
1
+
2
+ test_storage:
3
+ adapter: filesystem
4
+ directory: /home/phifty/projects/gom-filesystem-adapter/spec/acceptance/data
5
+ relation_detector: _id$
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gom-filesystem-adapter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - "Philipp Br\xC3\xBCll"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-08 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: gom
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 1
31
+ - 0
32
+ version: 0.1.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 2
45
+ version: "2"
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: reek
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 1
58
+ - 2
59
+ version: "1.2"
60
+ type: :development
61
+ version_requirements: *id003
62
+ description: Filesystem storage adapter for the General Object Mapper. Currently just read-only storage.
63
+ email: b.phifty@gmail.com
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files:
69
+ - README.rdoc
70
+ files:
71
+ - README.rdoc
72
+ - LICENSE
73
+ - Rakefile
74
+ - lib/gom/storage/filesystem/adapter.rb
75
+ - lib/gom/storage/filesystem/loader.rb
76
+ - lib/gom/storage/filesystem.rb
77
+ - lib/gom/storage.rb
78
+ - lib/filesystem.rb
79
+ - spec/gom/storage/filesystem/adapter_spec.rb
80
+ - spec/gom/storage/filesystem/loader_spec.rb
81
+ - spec/storage.configuration
82
+ - spec/spec_helper.rb
83
+ - spec/acceptance/data/Object.yml
84
+ - spec/acceptance/adapter_spec.rb
85
+ has_rdoc: true
86
+ homepage: http://github.com/phifty/gom-filesystem-adapter
87
+ licenses: []
88
+
89
+ post_install_message:
90
+ rdoc_options: []
91
+
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirements: []
111
+
112
+ rubyforge_project: gom-filesystem-adapter
113
+ rubygems_version: 1.3.7
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Filesystem storage adapter for the General Object Mapper.
117
+ test_files:
118
+ - spec/gom/storage/filesystem/adapter_spec.rb
119
+ - spec/gom/storage/filesystem/loader_spec.rb
120
+ - spec/acceptance/adapter_spec.rb