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 +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +48 -0
- data/lib/filesystem.rb +4 -0
- data/lib/gom/storage/filesystem/adapter.rb +47 -0
- data/lib/gom/storage/filesystem/loader.rb +87 -0
- data/lib/gom/storage/filesystem.rb +15 -0
- data/lib/gom/storage.rb +10 -0
- data/spec/acceptance/adapter_spec.rb +10 -0
- data/spec/acceptance/data/Object.yml +10 -0
- data/spec/gom/storage/filesystem/adapter_spec.rb +75 -0
- data/spec/gom/storage/filesystem/loader_spec.rb +77 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/storage.configuration +5 -0
- metadata +120 -0
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,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
|
data/lib/gom/storage.rb
ADDED
@@ -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,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
|
data/spec/spec_helper.rb
ADDED
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
|