dm-yaml-adapter 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,49 @@
1
+ dm-yaml-adapter
2
+
3
+ This adapter is for DataMapper. This allows you to persist objects to YAML files and still have the query capabilities of DataMapper. I wouldn't scale this out to a zillion files, but if you have a lot of read action on a small database this could be the project for you. OR use it to better understand DataMapper.
4
+
5
+
6
+ Example usage:
7
+
8
+ We have to tell datamapper where we will be storing the YAML files.
9
+ directory tells the adapter where to store.
10
+
11
+ DataMapper.setup(:default, {:adapter => 'yaml', :directory => 'db'})
12
+
13
+
14
+ Trying it out:
15
+
16
+ If you want some examples of defining classes, check out the spec directory.
17
+
18
+ Anyway, assuming you have a decent environment set up, you can try out some examples.
19
+
20
+ If you want to use irb to try some of this interactively, try 'irb' and then
21
+ > load 'irbhelper.irb'
22
+
23
+ That sets up a basic environment with User and Post resources already defined.
24
+
25
+ irb(main):001:0> load 'irbhelper.irb'
26
+ => true
27
+ irb(main):002:0> u = User.create(:name => 'Bob', :age => 55)
28
+ => #<User user_id=1 name="Bob" age=55>
29
+ irb(main):003:0> u.save
30
+ => true
31
+ irb(main):004:0> User.all
32
+ => [#<User user_id=1 name="Bob" age=55>]
33
+ irb(main):005:0>
34
+
35
+ If you use another window to check out the db directory you should have a nice User directory with a 1.yaml file in there, with the data of Bob.
36
+
37
+ You can also add another object and start playing around with some queries.
38
+
39
+ irb(main):005:0> User.create(:name => 'Sue', :age => 32)
40
+ => #<User user_id=2 name="Sue" age=32>
41
+ irb(main):006:0> User.all(:age => 32)
42
+ => [#<User user_id=2 name="Sue" age=32>]
43
+ irb(main):007:0> User.all
44
+ => [#<User user_id=1 name="Bob" age=55>, #<User user_id=2 name="Sue" age=32>]
45
+ irb(main):008:0> u.destroy
46
+ => true
47
+ irb(main):009:0> User.all
48
+ => [#<User user_id=2 name="Sue" age=32>]
49
+ irb(main):010:0>
@@ -0,0 +1,189 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+ require 'yaml'
4
+ require 'dm-core/adapters/abstract_adapter'
5
+
6
+ module DataMapper::Adapters
7
+
8
+ class YamlAdapter < AbstractAdapter
9
+
10
+ def initialize(name, options)
11
+ super
12
+
13
+ @options = Hash.new
14
+
15
+ @options[:directory] = options[:directory]
16
+
17
+ @options[:directory] ||= './db'
18
+
19
+ end
20
+
21
+ def destroy_model_storage(repository, model)
22
+ FileUtils.rm_rf(classname_to_dir(model.to_s))
23
+ end
24
+
25
+ def create_model_storage(repository, model)
26
+ FileUtils.mkdir_p(classname_to_dir(model.to_s))
27
+ end
28
+
29
+ def create(resources)
30
+ resources.each do |resource|
31
+ model = resource.model
32
+ id = find_free_id_for(resource.class.to_s)
33
+ # find name of key attribute
34
+ key = model.key.first.name
35
+ resource.attributes[key] = id
36
+ resource.instance_variable_set("@" + key.to_s, id)
37
+ save(resource)
38
+ end
39
+ return resources.size
40
+ end
41
+
42
+ def delete(query)
43
+ resultset = yaml_query(query)
44
+ resultset.each do |result|
45
+ yaml_destroy(result)
46
+ end
47
+ return resultset.size
48
+ end
49
+
50
+ def read_one(query)
51
+ return(filter_result_set(get_all(query.model), query).first)
52
+ end
53
+
54
+ def update(attributes, query)
55
+ # ok, for each object found we have to update the attribs we found
56
+ # first thing is figure out what class we are dealing with
57
+ clazz = query.model
58
+ # next, get all the matching objects
59
+ objs = filter_result_set(clazz.all, query)
60
+ # iterate over every object in this set and set the given attributes
61
+ objs.each do |obj|
62
+ attributes.each do |attrib|
63
+ # attrib is an array
64
+ # first member is Property object
65
+ # second member is the value
66
+ obj.instance_variable_set("@" + attrib[0].name.to_s, attrib[1])
67
+ end
68
+ save(obj)
69
+ end
70
+ end
71
+
72
+ def read_many(query)
73
+ return filter_result_set(get_all(query.model), query)
74
+ end
75
+
76
+
77
+ private
78
+
79
+ def yaml_destroy(resource)
80
+ # take an objects class and ID and figure
81
+ # out what file it's in
82
+ # and then remove that file
83
+ class_name = resource.class.to_s
84
+ id = resource.key.first
85
+ file = class_name_to_file(class_name, id)
86
+ File.unlink(file)
87
+ end
88
+
89
+ def yaml_query(query)
90
+ # in this method, we want to take each condition and figure out
91
+ # what we should return
92
+
93
+ # first is figuring out our class
94
+ model = query.model
95
+ # if we just want all the objects...
96
+ if (query.conditions.empty?)
97
+ return get_all(model)
98
+ end
99
+
100
+ # otherwise we have to filter on some conditions...
101
+ all_objs = get_all(model)
102
+ # for each object, check all the conditions
103
+ filter_result_set(all_objs, query)
104
+ end
105
+
106
+ def filter_result_set(objects, query)
107
+ result_set = objects.clone
108
+ objects.each do |obj|
109
+ query.conditions.each do |operator, property, value|
110
+ case operator
111
+ # handle eql
112
+ when :eql, :like
113
+ if ! (obj.instance_variable_get("@" + property.field) == value)
114
+ # remove from teh result set...
115
+ result_set.delete(obj)
116
+ end
117
+ # handle :not
118
+ when :not
119
+ if (obj.instance_variable_get("@" + property.field) == value)
120
+ result_set.delete(obj)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ return result_set
126
+ end
127
+
128
+ def get_all(clazz)
129
+ objects = Array.new
130
+ directory = classname_to_dir(clazz.to_s)
131
+ if ! File.exists?(directory)
132
+ return objects
133
+ end
134
+ Dir.entries(directory).grep(/\.yaml$/).each do |entry|
135
+ objects << file_to_object(File.join(directory, entry))
136
+ end
137
+ return objects
138
+ end
139
+
140
+ def file_to_object(file)
141
+ new_obj = YAML.load_file(file)
142
+ new_obj.instance_variable_set("@new_record", false)
143
+ return new_obj
144
+ end
145
+
146
+ def find_free_id_for(class_name)
147
+ # if there are no entries in the directory, or the directory doesn't exist
148
+ # we need to create it...
149
+
150
+ if ! File.exists?(classname_to_dir(class_name))
151
+ # default ID
152
+ return 1
153
+ end
154
+ directory = classname_to_dir(class_name)
155
+ if directory.entries.size == 0
156
+ return 1
157
+ end
158
+ free_id = -1
159
+ id = 1
160
+ until free_id != -1 do
161
+ id += 1
162
+ if ! File.exists?(File.join(directory, id.to_s + ".yaml"))
163
+ return id
164
+ end
165
+ end
166
+ end
167
+
168
+ def save(resource)
169
+ file = File.join(class_name_to_file(resource.class.to_s, resource.id))
170
+ # see if the directory exists, if it doesn't, we need to create it
171
+ if ! File.exists?(classname_to_dir(resource.class.to_s))
172
+ FileUtils.mkdir_p(classname_to_dir(resource.class.to_s))
173
+ end
174
+ yamlfile = File.new(class_name_to_file(resource.class.to_s, resource.id), "w")
175
+ yamlfile.puts resource.to_yaml
176
+ yamlfile.close
177
+ end
178
+
179
+ def classname_to_dir(class_name)
180
+ return File.join(@options[:directory], class_name.gsub("/", "_"))
181
+ end
182
+
183
+ def class_name_to_file(class_name, id)
184
+ return File.join(classname_to_dir(class_name), id.to_s + ".yaml")
185
+ end
186
+
187
+ end
188
+ end
189
+
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+ require 'dm-yaml-adapter'
4
+ require 'pathname'
5
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
6
+
7
+ describe DataMapper::Adapters::YamlAdapter do
8
+ before(:all) do
9
+ @adapter = DataMapper.setup(:default, {:adapter => 'yaml', :directory => 'db'})
10
+ User.auto_migrate!
11
+ @user1 = User.create(:name => 'tom')
12
+ @user2 = User.create(:name => 'jim')
13
+ end
14
+
15
+ describe "CRUD" do
16
+
17
+ describe "create" do
18
+ it "should create" do
19
+ @user1.user_id.should_not == nil
20
+ end
21
+ end
22
+
23
+ describe "read" do
24
+ it "should read all" do
25
+ begin
26
+ users = User.all
27
+ rescue Exception => e
28
+ puts e
29
+ puts e.backtrace
30
+ end
31
+ users.size.should_not == 0
32
+ end
33
+ end
34
+
35
+ describe "delete" do
36
+ it "should delete someone" do
37
+ user = User.create
38
+ user.destroy.should == true
39
+ end
40
+ end
41
+
42
+ describe "find not" do
43
+ it "should find someone with a not clause" do
44
+ users = User.all(:user_id.not => @user1.id)
45
+ users.first.user_id.should_not == @user1.id
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+
52
+ end
53
+
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+ require 'pathname'
4
+ require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-yaml-adapter'
5
+
6
+ class Post
7
+ include DataMapper::Resource
8
+
9
+ property :post_id, Serial
10
+ property :title, String
11
+
12
+ belongs_to :user
13
+ end
14
+
15
+ class User
16
+ include DataMapper::Resource
17
+
18
+ property :user_id, Serial
19
+ property :name, String
20
+ property :age, Integer
21
+
22
+ has n, :posts
23
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-yaml-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.5"
5
+ platform: ruby
6
+ authors:
7
+ - Joshua Harding
8
+ autorequire: dm-yaml-adapter
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-20 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: josh@statewidesoftware.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/dm-yaml-adapter.rb
26
+ - spec/dm-yaml-adapter_spec.rb
27
+ - spec/spec_helper.rb
28
+ - README
29
+ has_rdoc: true
30
+ homepage:
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project:
51
+ rubygems_version: 1.3.1
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: a YAML adapter for DataMapper. this (slow) adapter allows you to use DataMapper with YAML files as a backing store.
55
+ test_files:
56
+ - spec/dm-yaml-adapter_spec.rb
57
+ - spec/spec_helper.rb