yaml_record_rails_4 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +22 -0
- data/README.md +212 -0
- data/Rakefile +10 -0
- data/lib/yaml_record/adapters/local_store.rb +40 -0
- data/lib/yaml_record/adapters/redis_store.rb +42 -0
- data/lib/yaml_record/base.rb +425 -0
- data/lib/yaml_record/version.rb +3 -0
- data/lib/yaml_record_rails_4.rb +12 -0
- data/test/base_test.rb +216 -0
- data/test/test_helper.rb +16 -0
- data/yaml_record.gemspec +25 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7c8d16d47aacc32b9e9872265a47b59692127196
|
4
|
+
data.tar.gz: f5aa8767e80cf7b8d82a69e9dae554e6a3073c6a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 649b1d603d11fcbc1ca96795f97f8db64ddea172989d50bc3b0dc648b49f8240bf160916fb5dc93ce43ec57101ac16277cc7a015171eb85afb31b9bdd80ddf0b
|
7
|
+
data.tar.gz: 843b4a98521e65482e2dfaafcbb2843546b2b845d274d78a7fce68d433b224faaf8c37babdc41433130bcf98c1ff113c4c6ada2e79b5542d50e2fb83a2de1893
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011, Nico Taing, Miso, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
# YAML RECORD #
|
2
|
+
|
3
|
+
## Introduction ##
|
4
|
+
|
5
|
+
YAML Record is a data persistence library that complies with the ActiveModel API. Using YAMLRecord should be familiar to anyone that has used ActiveRecord before to manage your database. Using this library, the data is persisted in a YAML backed file.
|
6
|
+
|
7
|
+
## Rationale ##
|
8
|
+
|
9
|
+
*Why a YAML-based persistence store?* In certain situations, there are collections of simple data in which there are very few records which are by nature infrequently accessed and that are ideally able to be scanned easily within a text file. These can include a simple contact form, landing page interest, feedback forms, surveys, team pages, etc where there is simply no need for the overhead of a fully persisted database solution.
|
10
|
+
|
11
|
+
There are many cases where YAMLRecord is **not the correct** persistence strategy. Any collection that is going to have substantial number of records, will be frequently updated, or is accessible by a large volume of users should not be stored in a YAML text file for obvious reasons. However, for specific cases, the convenience of storing things in a simple text file becomes apparent. Being able to access the text file data as if the records were in a familiar database ORM has many conveniences and advantages such as keeping the controllers standard and leveraging existing ORM knowledge.
|
12
|
+
|
13
|
+
## Installation ##
|
14
|
+
|
15
|
+
Install using rubygems:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
gem install yaml_record
|
19
|
+
```
|
20
|
+
|
21
|
+
Or add gem to your Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# Gemfile
|
25
|
+
gem 'yaml_record'
|
26
|
+
# OR if you're using Rails 3.1
|
27
|
+
gem 'yaml_record' :git => "git@github.com:Nico-Taing/yaml_record.git", :branch => "rails31"
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage ##
|
31
|
+
|
32
|
+
### Declaration ###
|
33
|
+
|
34
|
+
Create any ruby object and inherit from `YamlRecord:Base` to define a type:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class Post < YamlRecord::Base
|
38
|
+
# Declare your properties
|
39
|
+
properties :title, :body, :user_id
|
40
|
+
|
41
|
+
# Declare your adapter (local by default)
|
42
|
+
adapter :local # or :redis
|
43
|
+
|
44
|
+
# Declare source file path
|
45
|
+
source Rails.root.join("config/posts")
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Use this new object the same way as any ActiveRecord object.
|
50
|
+
|
51
|
+
### Retrieval ###
|
52
|
+
|
53
|
+
Retrieve the collection:
|
54
|
+
|
55
|
+
Post.all => [@p1, @p2]
|
56
|
+
|
57
|
+
Retrieve item by id:
|
58
|
+
|
59
|
+
Post.find("a1b2") => @p1
|
60
|
+
|
61
|
+
Retrieve by attribute:
|
62
|
+
|
63
|
+
Post.find_by_attribute(:title, "some title") => @p
|
64
|
+
|
65
|
+
### Create ###
|
66
|
+
|
67
|
+
Initialize post:
|
68
|
+
|
69
|
+
@p = Post.new(:title => "...", :body => "...", :user_id => 5)
|
70
|
+
@p.save
|
71
|
+
|
72
|
+
Create post:
|
73
|
+
|
74
|
+
@p = Post.create(:title => "...", :body => "...", :user_id => 6)
|
75
|
+
|
76
|
+
### Update ###
|
77
|
+
|
78
|
+
Update attributes using the expected method:
|
79
|
+
|
80
|
+
@p.update_attributes(:title => "new title")
|
81
|
+
|
82
|
+
### Destroy ###
|
83
|
+
|
84
|
+
Destroy a given record:
|
85
|
+
|
86
|
+
@p.destroy
|
87
|
+
|
88
|
+
### Access ###
|
89
|
+
|
90
|
+
Access attributes:
|
91
|
+
|
92
|
+
@p = Post.find("a1b2")
|
93
|
+
@p.title => "..."
|
94
|
+
|
95
|
+
Assign attributes:
|
96
|
+
|
97
|
+
@p.title = "new title"
|
98
|
+
@p.save
|
99
|
+
|
100
|
+
### Callbacks ###
|
101
|
+
|
102
|
+
Create callbacks:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Submission < YamlRecord::Base
|
106
|
+
# ...
|
107
|
+
before_create :do_something # or before_save, before_destroy, ...
|
108
|
+
|
109
|
+
def do_something
|
110
|
+
# something here
|
111
|
+
end
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
## Storage Adapters ##
|
116
|
+
|
117
|
+
YAMLRecord supports pluggable storage adapters that control the storage engine used for the YAML data. By default, the adapter used is the
|
118
|
+
`local` store which writes a file (specified by `source` path) to the local system. There are currently two available adapters: `Local` and `Redis`.
|
119
|
+
|
120
|
+
To configure the adapter, you can simply declare within the object:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class Submission < YamlRecord::Base
|
124
|
+
adapter :redis, $redis # Second parameter is the redis client instance
|
125
|
+
source "contacts" # stores yaml namespaced as 'yaml_record:contacts' in redis
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Each storage adapter only defines a `read` and `write` interface and is easy to create.
|
130
|
+
Checkout the [redis adapter](https://github.com/Nico-Taing/yaml_record/blob/master/lib/yaml_record/adapters/redis_store.rb) for an example of how simple they are to define.
|
131
|
+
Feel free to create additional adapters and send them to us via a pull request.
|
132
|
+
|
133
|
+
## Example ##
|
134
|
+
|
135
|
+
Imagine a simple contact form that accepts a name and email from a user along with a body:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
class Submission < YamlRecord::Base
|
139
|
+
# Declare your properties
|
140
|
+
properties :name, :email, :body
|
141
|
+
|
142
|
+
# Declare your adapter (local by default)
|
143
|
+
adapter :local # or :redis
|
144
|
+
|
145
|
+
# Declare source file path (config/contact.yml)
|
146
|
+
source Rails.root.join("config/contact")
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
Once we define the Contact model, we can setup a controller and form just the same as in ActiveRecord:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
class SubmissionsController < AC::Base
|
154
|
+
def create
|
155
|
+
@submission = Submission.create(params[:submission])
|
156
|
+
end
|
157
|
+
|
158
|
+
def index
|
159
|
+
@submissions = Submission.all
|
160
|
+
end
|
161
|
+
|
162
|
+
def show
|
163
|
+
@submission = Submission.find(params[:id])
|
164
|
+
end
|
165
|
+
|
166
|
+
def update
|
167
|
+
@submission = Submission.find(params[:id])
|
168
|
+
@submission.update_attributes(params[:submission])
|
169
|
+
end
|
170
|
+
|
171
|
+
def destroy
|
172
|
+
@submission = Submission.find(params[:id])
|
173
|
+
@submission.destroy
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
As you can see the controller appears the same as any ActiveRecord controller would and this makes managing the YAML data easy and convenient. You can even define callbacks in your object as you would in ActiveRecord:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
class Submission < YamlRecord::Base
|
182
|
+
# ...
|
183
|
+
before_create :do_something # or before_save, before_destroy, ...
|
184
|
+
|
185
|
+
def do_something
|
186
|
+
# something here
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
And that's all! Each record will be persisted to the source file for easy access.
|
192
|
+
|
193
|
+
## Issues ##
|
194
|
+
|
195
|
+
* Validations should be supported `validates_presence_of :name`
|
196
|
+
* Property type declarations should be available `property :age, Integer`
|
197
|
+
|
198
|
+
## Contributors ##
|
199
|
+
|
200
|
+
Created at Miso by Nico Taing and Nathan Esquenazi
|
201
|
+
|
202
|
+
Special thanks to [Vaudoc](https://github.com/vaudoc)
|
203
|
+
|
204
|
+
Contributors and patches are welcome! Please send a pull request!
|
205
|
+
|
206
|
+
## Notes ##
|
207
|
+
|
208
|
+
There is already an excellent project for YAML persistence if you are using [Datamapper](https://github.com/datamapper/dm-yaml-adapter). In the situation in which we were using DM and [Padrino](http://padrinorb.com), this would surely be a better choice. But if you are using ActiveRecord and Rails, this library is a lightweight and standalone solution.
|
209
|
+
|
210
|
+
## License ##
|
211
|
+
|
212
|
+
YAML Record is Copyright © 2011 Nico Taing, Miso. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# YAML Adapter for using a local file store
|
2
|
+
|
3
|
+
module YamlRecord
|
4
|
+
module Adapters
|
5
|
+
class LocalStore
|
6
|
+
|
7
|
+
# Returns YAML File as ruby collection
|
8
|
+
#
|
9
|
+
# === Example:
|
10
|
+
#
|
11
|
+
# @adapter.read("foo") => [{...}, {...}]
|
12
|
+
#
|
13
|
+
def read(source, dynamic_source, source_file_name)
|
14
|
+
dir_path = source + dynamic_source
|
15
|
+
full_path = dir_path + source_file_name
|
16
|
+
|
17
|
+
Dir::mkdir(dir_path) unless File.directory?(dir_path)
|
18
|
+
File.open(full_path, 'w') unless File.exists?(full_path)
|
19
|
+
|
20
|
+
YAML.load_file(source + dynamic_source + source_file_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Writes ruby collection as YAML File
|
24
|
+
#
|
25
|
+
# === Example:
|
26
|
+
#
|
27
|
+
# @adapter.write("foo", [{...}, {...}]) => "<yaml data>"
|
28
|
+
#
|
29
|
+
def write(source, source_file_name, dynamic_source, collection)
|
30
|
+
dir_path = source + dynamic_source
|
31
|
+
full_path = dir_path + source_file_name
|
32
|
+
|
33
|
+
Dir::mkdir(dir_path) unless File.directory?(dir_path)
|
34
|
+
File.open(full_path, 'w') unless File.exists?(full_path)
|
35
|
+
|
36
|
+
File.open(source + dynamic_source + source_file_name, 'w') {|f| f.write(collection.to_yaml) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# YAML Adapter for using a redis client store
|
2
|
+
# YamlRecord::Adapters::RedisStore.new(@redis)
|
3
|
+
|
4
|
+
module YamlRecord
|
5
|
+
module Adapters
|
6
|
+
class RedisStore
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
# client is an instantiated redis client (i.e Redis::Client.new(...))
|
10
|
+
def initialize(client)
|
11
|
+
raise "Please specify a Redis client" unless client
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns Redis YML data as ruby collection
|
16
|
+
#
|
17
|
+
# === Example:
|
18
|
+
#
|
19
|
+
# @adapter.read("foo") => [{...}, {...}]
|
20
|
+
#
|
21
|
+
def read(source)
|
22
|
+
YAML.load(@client.get(redis_key(source)).to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Writes ruby collection as Redis YML data
|
26
|
+
#
|
27
|
+
# === Example:
|
28
|
+
#
|
29
|
+
# @adapter.write("foo", [{...}, {...}]) => "<yaml data>"
|
30
|
+
#
|
31
|
+
def write(source, collection)
|
32
|
+
@client.set(redis_key(source), collection.to_yaml)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def redis_key(source)
|
38
|
+
"yaml_record:" + source
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,425 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module YamlRecord
|
4
|
+
class Base
|
5
|
+
attr_accessor :attributes, :is_created, :is_destroyed
|
6
|
+
|
7
|
+
include ActiveModel::Conversion
|
8
|
+
include ActiveModel::Validations
|
9
|
+
include ActiveModel::Callbacks
|
10
|
+
include ActiveModel::Validations::Callbacks
|
11
|
+
|
12
|
+
define_model_callbacks :create, :save, :destroy, :update, :validation, :initialize
|
13
|
+
|
14
|
+
before_create :set_id!
|
15
|
+
|
16
|
+
# Constructs a new YamlRecord instance based on specified attribute hash
|
17
|
+
#
|
18
|
+
# === Example:
|
19
|
+
#
|
20
|
+
# class Post < YamlRecord::Base; properties :foo; end
|
21
|
+
#
|
22
|
+
# Post.new(:foo => "bar")
|
23
|
+
#
|
24
|
+
def initialize(attr_hash={})
|
25
|
+
attr_hash.symbolize_keys!
|
26
|
+
attr_hash.reverse_merge!(self.class.properties.inject({}) { |result, key| result[key] = nil; result })
|
27
|
+
|
28
|
+
self.attributes ||= {}
|
29
|
+
self.is_created = attr_hash.delete(:persisted) || false
|
30
|
+
attr_hash.each do |k,v|
|
31
|
+
self.send("#{k}=", v) # self.attributes[:media] = "foo"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Accesses given attribute from YamlRecord instance
|
36
|
+
#
|
37
|
+
# === Example:
|
38
|
+
#
|
39
|
+
# @post[:foo] => "bar"
|
40
|
+
#
|
41
|
+
def [](attribute)
|
42
|
+
self.attributes[attribute]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Assign given attribute from YamlRecord instance with specified value
|
46
|
+
#
|
47
|
+
# === Example:
|
48
|
+
#
|
49
|
+
# @post[:foo] = "baz"
|
50
|
+
#
|
51
|
+
def []=(attribute, value)
|
52
|
+
self.attributes[attribute] = value
|
53
|
+
end
|
54
|
+
|
55
|
+
# Saved YamlRecord instance to file
|
56
|
+
# Executes save and create callbacks
|
57
|
+
# Returns true if record saved; false otherwise
|
58
|
+
#
|
59
|
+
# === Example:
|
60
|
+
#
|
61
|
+
# @post.save => true
|
62
|
+
#
|
63
|
+
def save
|
64
|
+
run_callbacks(:save) { false }
|
65
|
+
run_callbacks(:create) { false } unless self.is_created
|
66
|
+
|
67
|
+
existing_items = self.class.all(dynamic_source)
|
68
|
+
if self.new_record?
|
69
|
+
existing_items << self
|
70
|
+
else # update existing record
|
71
|
+
updated_item = existing_items.find { |item| item.id == self.id }
|
72
|
+
return false unless updated_item
|
73
|
+
updated_item.attributes = self.attributes
|
74
|
+
end
|
75
|
+
|
76
|
+
raw_data = existing_items ? existing_items.map { |item| item.persisted_attributes } : []
|
77
|
+
self.class.write_contents(dynamic_source, raw_data) if self.valid?
|
78
|
+
|
79
|
+
run_callbacks(:create) { true } unless self.is_created
|
80
|
+
run_callbacks(:save) { true }
|
81
|
+
true
|
82
|
+
rescue IOError
|
83
|
+
false
|
84
|
+
end
|
85
|
+
|
86
|
+
# Update YamlRecord instance with specified attributes
|
87
|
+
# Returns true if record updated; false otherwise
|
88
|
+
#
|
89
|
+
# === Example:
|
90
|
+
#
|
91
|
+
# @post.update_attributes(:foo => "baz", :miso => "awesome") => true
|
92
|
+
#
|
93
|
+
def update_attributes(updated_attrs={})
|
94
|
+
updated_attrs.each { |k,v| self.send("#{k}=", v) }
|
95
|
+
self.save
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns array of instance attributes names; An attribute is a value stored for this record (persisted or not)
|
99
|
+
#
|
100
|
+
# === Example:
|
101
|
+
#
|
102
|
+
# @post.column_names => ["foo", "miso"]
|
103
|
+
#
|
104
|
+
def column_names
|
105
|
+
array = []
|
106
|
+
self.attributes.each_key { |k| array << k.to_s }
|
107
|
+
array
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns hash of attributes to be persisted to file.
|
111
|
+
# A persisted attribute is a value stored in the file (specified with the properties declaration)
|
112
|
+
#
|
113
|
+
# === Example:
|
114
|
+
#
|
115
|
+
# class Post < YamlRecord::Base; properties :foo, :miso; end
|
116
|
+
# @post = Post.create(:foo => "bar", :miso => "great")
|
117
|
+
# @post.persisted_attributes => { :id => "a1b2c3", :foo => "bar", :miso => "great" }
|
118
|
+
#
|
119
|
+
def persisted_attributes
|
120
|
+
self.attributes.slice(*self.class.properties).reject { |k, v| v.nil? }
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns true if YamlRecord instance hasn't persisted; false otherwise
|
124
|
+
#
|
125
|
+
# === Example:
|
126
|
+
#
|
127
|
+
# @post = Post.new(:foo => "bar", :miso => "great")
|
128
|
+
# @post.new_record? => true
|
129
|
+
# @post.save => true
|
130
|
+
# @post.new_record? => false
|
131
|
+
#
|
132
|
+
def new_record?
|
133
|
+
!self.is_created
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns true if YamlRecord instance has been destroyed; false otherwise
|
137
|
+
#
|
138
|
+
# === Example:
|
139
|
+
#
|
140
|
+
# @post = Post.new(:foo => "bar", :miso => "great")
|
141
|
+
# @post.destroyed? => false
|
142
|
+
# @post.save
|
143
|
+
# @post.destroy => true
|
144
|
+
# @post.destroyed? => true
|
145
|
+
#
|
146
|
+
def destroyed?
|
147
|
+
self.is_destroyed
|
148
|
+
end
|
149
|
+
|
150
|
+
# Remove a persisted YamlRecord object
|
151
|
+
# Returns true if destroyed; false otherwise
|
152
|
+
#
|
153
|
+
# === Example:
|
154
|
+
#
|
155
|
+
# @post = Post.create(:foo => "bar", :miso => "great")
|
156
|
+
# Post.all.size => 1
|
157
|
+
# @post.destroy => true
|
158
|
+
# Post.all.size => 0
|
159
|
+
#
|
160
|
+
def destroy
|
161
|
+
run_callbacks(:destroy) { false }
|
162
|
+
new_data = self.class.all.reject { |item| item.persisted_attributes == self.persisted_attributes }.map { |item| item.persisted_attributes }
|
163
|
+
self.class.write_contents(dynamic_source, new_data)
|
164
|
+
self.is_destroyed = true
|
165
|
+
run_callbacks(:destroy) { true }
|
166
|
+
true
|
167
|
+
rescue IOError
|
168
|
+
false
|
169
|
+
end
|
170
|
+
|
171
|
+
# Execute validations for instance
|
172
|
+
# Returns true if record is valid; false otherwise
|
173
|
+
# TODO Implement validation
|
174
|
+
#
|
175
|
+
# === Example:
|
176
|
+
#
|
177
|
+
# @post.valid? => true
|
178
|
+
#
|
179
|
+
def valid?
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns errors messages if record isn't valid; empty array otherwise
|
184
|
+
# TODO Implement validation
|
185
|
+
#
|
186
|
+
# === Example:
|
187
|
+
#
|
188
|
+
# @post.errors => ["Foo can't be blank"]
|
189
|
+
#
|
190
|
+
def errors
|
191
|
+
[]
|
192
|
+
end
|
193
|
+
|
194
|
+
# Returns YamlRecord Instance
|
195
|
+
# Complies with ActiveModel api
|
196
|
+
#
|
197
|
+
# === Example:
|
198
|
+
#
|
199
|
+
# @post.to_model => @post
|
200
|
+
#
|
201
|
+
def to_model
|
202
|
+
self
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns the instance of a record as a parameter
|
206
|
+
# By default return an id
|
207
|
+
#
|
208
|
+
# === Example:
|
209
|
+
#
|
210
|
+
# @post.to_param => <id>
|
211
|
+
#
|
212
|
+
def to_param
|
213
|
+
self.id
|
214
|
+
end
|
215
|
+
|
216
|
+
# Reload YamlRecord instance attributes from file
|
217
|
+
#
|
218
|
+
# === Example:
|
219
|
+
#
|
220
|
+
# @post = Post.create(:foo => "bar", :miso => "great")
|
221
|
+
# @post.foo = "bazz"
|
222
|
+
# @post.reload
|
223
|
+
# @post.foo => "bar"
|
224
|
+
#
|
225
|
+
def reload
|
226
|
+
record = self.class.find(self.id)
|
227
|
+
self.attributes = record.attributes
|
228
|
+
record
|
229
|
+
end
|
230
|
+
|
231
|
+
# Find YamlRecord instance given attribute name and expected value
|
232
|
+
# Supports checking inclusion for array based values
|
233
|
+
# Returns instance if found; false otherwise
|
234
|
+
#
|
235
|
+
# === Example:
|
236
|
+
#
|
237
|
+
# Post.find_by_attribute(:foo, "bar") => @post
|
238
|
+
# Post.find_by_attribute(:some_list, "item") => @post
|
239
|
+
#
|
240
|
+
def self.find_by_attribute(dynamic_source='default', attribute, expected_value)
|
241
|
+
self.all(dynamic_source).find do |record|
|
242
|
+
value = record.send(attribute) if record.respond_to?(attribute)
|
243
|
+
value.is_a?(Array) ?
|
244
|
+
value.include?(expected_value) :
|
245
|
+
value == expected_value
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class << self;
|
250
|
+
|
251
|
+
# Find YamlRecord instance given id
|
252
|
+
# Returns instance if found; false otherwise
|
253
|
+
#
|
254
|
+
# === Example:
|
255
|
+
#
|
256
|
+
# Post.find_by_id("a1b2c3") => @post
|
257
|
+
#
|
258
|
+
def find_by_id(dynamic_source='default', value)
|
259
|
+
self.find_by_attribute(dynamic_source, :id, value)
|
260
|
+
end
|
261
|
+
alias :find :find_by_id
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns collection of all YamlRecord instances
|
265
|
+
# Caches results during request
|
266
|
+
#
|
267
|
+
# === Example:
|
268
|
+
#
|
269
|
+
# Post.all => [@post1, @post2, ...]
|
270
|
+
# Post.all(true) => (...force reload...)
|
271
|
+
#
|
272
|
+
def self.all(dynamic_source='default')
|
273
|
+
raw_items = self.adapter.read(self.source, dynamic_source, self.source_file_name) || []
|
274
|
+
raw_items.map { |item| self.new(item.merge(:persisted => true)) }
|
275
|
+
end
|
276
|
+
|
277
|
+
# Find last YamlRecord instance given a limit
|
278
|
+
# Returns an array of instances if found; empty otherwise
|
279
|
+
#
|
280
|
+
# === Example:
|
281
|
+
#
|
282
|
+
# Post.last => @post6
|
283
|
+
# Post.last(3) => [@p4, @p5, @p6]
|
284
|
+
#
|
285
|
+
def self.last(dynamic_source='default', limit=1)
|
286
|
+
limit == 1 ? self.all(dynamic_source).last : self.all(dynamic_source).last(limit)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Find first YamlRecord instance given a limit
|
290
|
+
# Returns an array of instances if found; empty otherwise
|
291
|
+
#
|
292
|
+
# === Example:
|
293
|
+
#
|
294
|
+
# Post.first => @post
|
295
|
+
# Post.first(3) => [@p1, @p2, @p3]
|
296
|
+
#
|
297
|
+
def self.first(dynamic_source='default', limit=1)
|
298
|
+
limit == 1 ? self.all(dynamic_source).first : self.all(dynamic_source).first(limit)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Initializes YamlRecord instance given an attribute hash and saves afterwards
|
302
|
+
# Returns instance if successfully saved; false otherwise
|
303
|
+
#
|
304
|
+
# === Example:
|
305
|
+
#
|
306
|
+
# Post.create(:foo => "bar", :miso => "great") => @post
|
307
|
+
#
|
308
|
+
def self.create(attributes={})
|
309
|
+
@fs = self.new(attributes)
|
310
|
+
if @fs.save == true
|
311
|
+
@fs.is_created = true;
|
312
|
+
@fs
|
313
|
+
else
|
314
|
+
false
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# Declares persisted attributes for YamlRecord class
|
319
|
+
#
|
320
|
+
# === Example:
|
321
|
+
#
|
322
|
+
# class Post < YamlRecord::Base; properties :foo, :miso; end
|
323
|
+
# Post.create(:foo => "bar", :miso => "great") => @post
|
324
|
+
#
|
325
|
+
def self.properties(*names)
|
326
|
+
@_properties ||= []
|
327
|
+
if names.size == 0 # getter
|
328
|
+
@_properties
|
329
|
+
elsif names.size > 0 # setter
|
330
|
+
names = names | [:id]
|
331
|
+
setup_properties!(*names)
|
332
|
+
@_properties += names
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# Declares or retrieves adapter for Yaml storage
|
337
|
+
# Returns an instance of an adapter
|
338
|
+
#
|
339
|
+
# === Example:
|
340
|
+
#
|
341
|
+
# class Post < YamlRecord::Base
|
342
|
+
# adapter :redis, @redis # => YamlRecord::Adapters::RedisAdapter
|
343
|
+
# end
|
344
|
+
#
|
345
|
+
def self.adapter(kind=nil, *options)
|
346
|
+
kind.nil? ? @_adapter_kind ||= :local : @_adapter_kind = kind
|
347
|
+
@_adapter ||= eval("YamlRecord::Adapters::#{@_adapter_kind.to_s.capitalize}Store").new(*options)
|
348
|
+
end
|
349
|
+
|
350
|
+
# Declares source file for YamlRecord class
|
351
|
+
#
|
352
|
+
# === Example:
|
353
|
+
#
|
354
|
+
# class Post < YamlRecord::Base
|
355
|
+
# source "path/to/yaml/file"
|
356
|
+
# end
|
357
|
+
#
|
358
|
+
def self.source(file=nil)
|
359
|
+
file ? @file = (file.to_s) : @file
|
360
|
+
end
|
361
|
+
|
362
|
+
# Declares source_file_name for YamlRecord class
|
363
|
+
#
|
364
|
+
# === Example:
|
365
|
+
#
|
366
|
+
# class Post < YamlRecord::Base
|
367
|
+
# source_file_name "file_name"
|
368
|
+
# end
|
369
|
+
#
|
370
|
+
def self.source_file_name(source_file_name=nil)
|
371
|
+
source_file_name ? @source_file_name = (source_file_name.to_s + ".yml") : @source_file_name
|
372
|
+
end
|
373
|
+
|
374
|
+
# Overrides equality to match if matching ids
|
375
|
+
#
|
376
|
+
def ==(comparison_record)
|
377
|
+
self.id == comparison_record.id
|
378
|
+
end
|
379
|
+
|
380
|
+
protected
|
381
|
+
|
382
|
+
# Validates each persisted attributes
|
383
|
+
# TODO Implement validation
|
384
|
+
#
|
385
|
+
def self.validates_each(*args, &block)
|
386
|
+
true
|
387
|
+
end
|
388
|
+
|
389
|
+
# Write raw yaml data to file
|
390
|
+
# Protected method, not called during usage
|
391
|
+
#
|
392
|
+
# === Example:
|
393
|
+
#
|
394
|
+
# Post.write_content([{ :foo => "bar"}, { :foo => "baz"}, ...]) # writes to source file
|
395
|
+
#
|
396
|
+
def self.write_contents(dynamic_source, raw_data)
|
397
|
+
self.adapter.write(self.source, self.source_file_name, dynamic_source, raw_data)
|
398
|
+
@records = nil
|
399
|
+
end
|
400
|
+
|
401
|
+
# Creates reader and writer methods for each persisted attribute
|
402
|
+
# Protected method, not called during usage
|
403
|
+
#
|
404
|
+
# === Example:
|
405
|
+
#
|
406
|
+
# Post.setup_properties!(:foo)
|
407
|
+
# @post.foo = "baz"
|
408
|
+
# @post.foo => "baz"
|
409
|
+
#
|
410
|
+
def self.setup_properties!(*names)
|
411
|
+
names.each do |name|
|
412
|
+
define_method(name) { self[name.to_sym] }
|
413
|
+
define_method("#{name}=") { |val| self[name.to_sym] = val }
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Assign YamlRecord a unique id if not set
|
418
|
+
# Invoke before create of an instance
|
419
|
+
# Protected method, not called during usage
|
420
|
+
#
|
421
|
+
def set_id!
|
422
|
+
self.id = SecureRandom.hex(15)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_support/core_ext/kernel'
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
require 'active_support/core_ext/hash'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'active_support/callbacks'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module YamlRecord
|
9
|
+
require File.dirname(__FILE__) + "/yaml_record/base"
|
10
|
+
require File.dirname(__FILE__) + "/yaml_record/adapters/redis_store"
|
11
|
+
require File.dirname(__FILE__) + "/yaml_record/adapters/local_store"
|
12
|
+
end
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class YamlObject < YamlRecord::Base
|
4
|
+
properties :title, :body, :child_ids
|
5
|
+
source File.dirname(__FILE__) + "/../tmp/yaml_object"
|
6
|
+
end
|
7
|
+
|
8
|
+
class BaseTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@obj_title = "Simple Title"
|
12
|
+
@obj_id = "1234"
|
13
|
+
@obj2_id = "5678"
|
14
|
+
@obj2_title = "Simple Title 2"
|
15
|
+
|
16
|
+
@attr = {
|
17
|
+
:child_ids => [@obj_id],
|
18
|
+
:title => @obj_title,
|
19
|
+
:body => "Body!!"
|
20
|
+
}
|
21
|
+
|
22
|
+
@attr2 = {
|
23
|
+
:child_ids => [@obj2_id],
|
24
|
+
:title => @obj2_title,
|
25
|
+
:body => "Body!!"
|
26
|
+
}
|
27
|
+
|
28
|
+
clean_yaml_record(YamlObject)
|
29
|
+
@fs = YamlObject.create(@attr)
|
30
|
+
end
|
31
|
+
|
32
|
+
context "for instance methods" do
|
33
|
+
|
34
|
+
context "for [] method" do
|
35
|
+
should("get attribute with [attribute]"){ assert_equal @fs.title, @fs[:title] }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "for []= method" do
|
39
|
+
setup do
|
40
|
+
@fs[:title] = "Toto"
|
41
|
+
end
|
42
|
+
should("set attribute with [attribute]="){ assert_equal @fs[:title], "Toto" }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "for save method" do
|
46
|
+
setup do
|
47
|
+
@fs2 = YamlObject.new(@attr)
|
48
|
+
@fs2.save
|
49
|
+
end
|
50
|
+
|
51
|
+
should("save on yaml file"){ assert_equal YamlObject.last.attributes.diff(@attr), {:id => @fs2.reload.id } }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "for update_attributes method" do
|
55
|
+
setup do
|
56
|
+
@fs.update_attributes(:title => "Toto", :body => "http://somewhereelse.com")
|
57
|
+
@fs.reload
|
58
|
+
end
|
59
|
+
should("update title") { assert_equal @fs.title, "Toto" }
|
60
|
+
should("update body") { assert_equal @fs.body, "http://somewhereelse.com" }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "for column_names method" do
|
64
|
+
should("return an array with attributes names") { assert_equal @fs.column_names.sort!, YamlObject.properties.map { |p| p.to_s }.sort! }
|
65
|
+
end
|
66
|
+
|
67
|
+
context "for persisted_attributes method" do
|
68
|
+
should("return persisted attributes") { assert_equal [:title, :body, :child_ids, :id ].sort_by {|sym| sym.to_s}, @fs.persisted_attributes.keys.sort_by {|sym| sym.to_s} }
|
69
|
+
end
|
70
|
+
|
71
|
+
context "for new_record? method" do
|
72
|
+
setup do
|
73
|
+
@fs3 = YamlObject.new
|
74
|
+
end
|
75
|
+
should("be a new record") { assert @fs3.new_record? }
|
76
|
+
should("not be a new record") { assert_false @fs.new_record? }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "for destroyed? method" do
|
80
|
+
setup do
|
81
|
+
@fs4 = YamlObject.create(@attr)
|
82
|
+
@fs4.destroy
|
83
|
+
end
|
84
|
+
should("be a destoyed") { assert @fs4.destroyed? }
|
85
|
+
should("not be destroyed") { assert_false @fs.destroyed? }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "for destroy method" do
|
89
|
+
setup do
|
90
|
+
@fs5 = YamlObject.create(@attr)
|
91
|
+
@fs5.destroy
|
92
|
+
end
|
93
|
+
should("not find @fs5"){ assert_nil YamlObject.find(@fs5.id) }
|
94
|
+
end
|
95
|
+
|
96
|
+
context "for reload method" do
|
97
|
+
setup do
|
98
|
+
@fs.title = "Foo"
|
99
|
+
end
|
100
|
+
should("equal to Foo"){ assert_equal @fs.title, "Foo" }
|
101
|
+
should("equal to correct title"){ assert_equal @fs.reload.title, @obj_title }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "for to_param method" do
|
105
|
+
setup { @fs.id = "a1b2c3" }
|
106
|
+
|
107
|
+
should("return id of record") { assert_equal(@fs.to_param, @fs.id) }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "for class methods" do
|
112
|
+
context "for self.find_by_attribute method" do
|
113
|
+
setup do
|
114
|
+
@fs_found = YamlObject.find_by_attribute(:title, @obj_title)
|
115
|
+
end
|
116
|
+
should("be same object as @fs"){ assert_equal @fs_found, YamlObject.find(@fs.id) }
|
117
|
+
end
|
118
|
+
|
119
|
+
context "for self.find_by_id method" do
|
120
|
+
setup do
|
121
|
+
@fs_found = YamlObject.find_by_id(@fs.id)
|
122
|
+
@fs_found2 = YamlObject.find(@fs.id)
|
123
|
+
end
|
124
|
+
should("be same object as @fs"){ assert_equal @fs.attributes, @fs_found.attributes }
|
125
|
+
should("be same object as @fs bis"){ assert_equal @fs.attributes, @fs_found2.attributes }
|
126
|
+
end
|
127
|
+
|
128
|
+
context "for self.all method" do
|
129
|
+
setup do
|
130
|
+
clean_yaml_record(YamlObject)
|
131
|
+
@fs, @fs2 = YamlObject.create(@attr), YamlObject.create(@attr2)
|
132
|
+
end
|
133
|
+
should("retrieve 2 YamlObject obj"){ assert_equal YamlObject.all.size, 2 }
|
134
|
+
should("return as first item @fs"){ assert_equal YamlObject.all.first.attributes, @fs.attributes }
|
135
|
+
should("return as last item @fs2"){ assert_equal YamlObject.all.last.attributes, @fs2.attributes }
|
136
|
+
end
|
137
|
+
|
138
|
+
context "for self.first method" do
|
139
|
+
setup do
|
140
|
+
clean_yaml_record(YamlObject)
|
141
|
+
@fs, @fs2 = YamlObject.create(@attr), YamlObject.create(@attr2)
|
142
|
+
end
|
143
|
+
|
144
|
+
should("return @fs as the first item"){ assert_equal YamlObject.first.attributes, @fs.attributes }
|
145
|
+
should("return @fs"){ assert_equal YamlObject.first(2).first.attributes, @fs.attributes }
|
146
|
+
should("return @fs2"){ assert_equal YamlObject.first(2).last.attributes, @fs2.attributes }
|
147
|
+
end
|
148
|
+
|
149
|
+
context "for self.last method" do
|
150
|
+
setup do
|
151
|
+
clean_yaml_record(YamlObject)
|
152
|
+
@fs, @fs2 = YamlObject.create(@attr), YamlObject.create(@attr2)
|
153
|
+
end
|
154
|
+
|
155
|
+
should("return @fs as the first item"){ assert_equal YamlObject.last.attributes, @fs2.attributes }
|
156
|
+
should("return @fs"){ assert_equal YamlObject.last(2).first.attributes, @fs.attributes }
|
157
|
+
should("return @fs2"){ assert_equal YamlObject.last(2).last.attributes, @fs2.attributes }
|
158
|
+
end
|
159
|
+
|
160
|
+
context "for self.write_contents method" do
|
161
|
+
setup do
|
162
|
+
clean_yaml_record(YamlObject)
|
163
|
+
@attributes = [ @attr, @attr2 ]
|
164
|
+
YamlObject.write_contents(@attributes)
|
165
|
+
end
|
166
|
+
should("write in yaml file"){ assert_equal YAML.load_file(YamlObject.source), [ @attr, @attr2 ] }
|
167
|
+
end
|
168
|
+
|
169
|
+
context "for self.create method" do
|
170
|
+
setup do
|
171
|
+
clean_yaml_record(YamlObject)
|
172
|
+
@fs = YamlObject.create(@attr)
|
173
|
+
@fs_not_created = YamlObject.new(@attr)
|
174
|
+
end
|
175
|
+
should("create @fs"){ assert_equal YamlObject.last.attributes, @fs.attributes }
|
176
|
+
should("set its is_created to true"){ assert @fs.is_created }
|
177
|
+
should("set @fs_not_created is_created field to false"){ assert_false @fs_not_created.is_created }
|
178
|
+
end
|
179
|
+
|
180
|
+
context "for self.adapter method" do
|
181
|
+
should("return local adapter") do
|
182
|
+
class YamlOtherObject < YamlRecord::Base; end
|
183
|
+
assert_kind_of YamlRecord::Adapters::LocalStore, YamlOtherObject.adapter
|
184
|
+
end
|
185
|
+
should("support explicit local adapter") do
|
186
|
+
YamlObject.adapter(:local)
|
187
|
+
assert_kind_of YamlRecord::Adapters::LocalStore, YamlObject.adapter
|
188
|
+
end
|
189
|
+
should("support changing adapter") do
|
190
|
+
class YamlRedisObject < YamlRecord::Base; end
|
191
|
+
@object = Object.new
|
192
|
+
YamlRedisObject.adapter(:redis, @object)
|
193
|
+
assert_kind_of YamlRecord::Adapters::RedisStore, YamlRedisObject.adapter
|
194
|
+
assert_equal @object, YamlRedisObject.adapter.client
|
195
|
+
class YamlOtherObject < YamlRecord::Base; end
|
196
|
+
assert_kind_of YamlRecord::Adapters::LocalStore, YamlOtherObject.adapter
|
197
|
+
end
|
198
|
+
should("not support invalid adapter") do
|
199
|
+
assert_raise(NameError) { class YamlFakeObject < YamlRecord::Base; adapter(:fake); end }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context "for set_id!" do
|
204
|
+
setup do
|
205
|
+
@fs_no_id = YamlObject.new(@attr)
|
206
|
+
@fs_with_id = YamlObject.create(@attr)
|
207
|
+
@id = @fs_with_id.id
|
208
|
+
@fs_with_id.update_attributes(:title => "Gomiso")
|
209
|
+
end
|
210
|
+
should("not have any id"){ assert_nil @fs_no_id.id }
|
211
|
+
should("have a id"){ assert @fs_with_id.id }
|
212
|
+
should("keep the same id"){ assert_equal @fs_with_id.id, @id }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require File.dirname(__FILE__) + "/../lib/yaml_record"
|
5
|
+
|
6
|
+
class Test::Unit::TestCase
|
7
|
+
def clean_yaml_record(class_record)
|
8
|
+
File.open(class_record.source, 'w') {|f| f.write(nil) }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Asserts that the condition is not true
|
12
|
+
# assert_false @title == "hey"
|
13
|
+
def assert_false(condition, message=nil)
|
14
|
+
assert !condition, message
|
15
|
+
end
|
16
|
+
end
|
data/yaml_record.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "yaml_record/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "yaml_record_rails_4"
|
7
|
+
s.version = YamlRecord::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Nico Taing", "Nathan Esquenazi", 'Ruslan Hamidullin', 'Eduard Gataullin']
|
10
|
+
s.email = ["edikgat@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/edikgat/yaml_record/tree/rails4"
|
12
|
+
s.summary = %q{This gem is a fork to gem yaml_record with rails 4 support}
|
13
|
+
s.description = %q{Use YAML for persisted data with ActiveModel interface}
|
14
|
+
|
15
|
+
s.rubyforge_project = "yaml_record_rails_4"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'activesupport', '~> 4.0.0'
|
23
|
+
s.add_development_dependency 'rake', '~> 1.5.2'
|
24
|
+
s.add_development_dependency 'shoulda'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yaml_record_rails_4
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nico Taing
|
8
|
+
- Nathan Esquenazi
|
9
|
+
- Ruslan Hamidullin
|
10
|
+
- Eduard Gataullin
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2013-09-20 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ~>
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.5.2
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.5.2
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: shoulda
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
description: Use YAML for persisted data with ActiveModel interface
|
59
|
+
email:
|
60
|
+
- edikgat@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- Gemfile
|
67
|
+
- MIT-LICENSE
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- lib/yaml_record/adapters/local_store.rb
|
71
|
+
- lib/yaml_record/adapters/redis_store.rb
|
72
|
+
- lib/yaml_record/base.rb
|
73
|
+
- lib/yaml_record/version.rb
|
74
|
+
- lib/yaml_record_rails_4.rb
|
75
|
+
- test/base_test.rb
|
76
|
+
- test/test_helper.rb
|
77
|
+
- yaml_record.gemspec
|
78
|
+
homepage: https://github.com/edikgat/yaml_record/tree/rails4
|
79
|
+
licenses: []
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project: yaml_record_rails_4
|
97
|
+
rubygems_version: 2.0.3
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: This gem is a fork to gem yaml_record with rails 4 support
|
101
|
+
test_files: []
|