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