dm-yaml-adapter 0.5

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/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