plain_record 0.1.0 → 0.2
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/.gitignore +8 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/.yardopts +4 -0
- data/ChangeLog +9 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +24 -0
- data/LICENSE +3 -4
- data/README.md +124 -0
- data/Rakefile +29 -41
- data/lib/plain_record.rb +22 -2
- data/lib/plain_record/association_proxy.rb +59 -0
- data/lib/plain_record/associations.rb +271 -0
- data/lib/plain_record/callbacks.rb +146 -0
- data/lib/plain_record/filepath.rb +141 -0
- data/lib/plain_record/model.rb +134 -61
- data/lib/plain_record/model/entry.rb +20 -8
- data/lib/plain_record/model/list.rb +30 -8
- data/lib/plain_record/resource.rb +76 -18
- data/lib/plain_record/version.rb +3 -0
- data/plain_record.gemspec +30 -0
- data/spec/associations_spec.rb +142 -0
- data/spec/callbacks_spec.rb +59 -0
- data/spec/data/1/comments.yml +5 -0
- data/spec/data/1/{post.m → post.md} +0 -0
- data/spec/data/2/{post.m → post.md} +1 -1
- data/spec/data/3/post.md +4 -0
- data/spec/data/authors/extern.yml +2 -2
- data/spec/data/authors/intern.yml +4 -4
- data/spec/data/best/4/post.md +1 -0
- data/spec/filepath_spec.rb +53 -0
- data/spec/model_spec.rb +100 -39
- data/spec/resource_spec.rb +84 -23
- data/spec/spec_helper.rb +33 -14
- metadata +119 -61
- data/README.rdoc +0 -92
- data/VERSION +0 -1
- data/spec/data/3/post.m +0 -1
File without changes
|
data/spec/data/3/post.md
ADDED
@@ -1,3 +1,3 @@
|
|
1
1
|
- name: Anonymous
|
2
|
-
-
|
3
|
-
|
2
|
+
- name: SuperHacker
|
3
|
+
login: super1997
|
@@ -1,4 +1,4 @@
|
|
1
|
-
-
|
2
|
-
|
3
|
-
-
|
4
|
-
|
1
|
+
- name: John Smith
|
2
|
+
login: john
|
3
|
+
- name: Ivan Ivanov
|
4
|
+
login: ivan
|
@@ -0,0 +1 @@
|
|
1
|
+
title: Best
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe PlainRecord::Filepath do
|
4
|
+
|
5
|
+
it "shouldn't create non-virtual filepath property" do
|
6
|
+
lambda {
|
7
|
+
Class.new do
|
8
|
+
include PlainRecord::Resource
|
9
|
+
entry_in 'data/*/post.md'
|
10
|
+
property :category, in_filepath(1)
|
11
|
+
end
|
12
|
+
}.should raise_error(ArgumentError, /virtual creator/)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should load filepath property" do
|
16
|
+
best = FilepathPost.first(:title => 'Best')
|
17
|
+
best.category.should == 'best/'
|
18
|
+
best.name.should == '4'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should load filepath property as nil when ** pattern is empty" do
|
22
|
+
FilepathPost.first(:title => 'First').category.should be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return more accurate path by filepath properties" do
|
26
|
+
FilepathPost.path(:name => 2).should == 'data/**/2/post.md'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should use filepath properties in search" do
|
30
|
+
FilepathPost.loaded = { }
|
31
|
+
FilepathPost.all(:category => 'best/')
|
32
|
+
FilepathPost.loaded.should have(1).keys
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should load properties from model constructor" do
|
36
|
+
post = FilepathPost.new(:name => 5)
|
37
|
+
post.name.should == 5
|
38
|
+
post.category.should be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should get entry path by filepath properties" do
|
42
|
+
path = File.join(File.dirname(__FILE__), 'data/5/post.md')
|
43
|
+
post = FilepathPost.new(:name => 5, :category => '')
|
44
|
+
FilepathPost.should_receive(:move_entry).with(post, nil, path)
|
45
|
+
post.save
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise error, when can't get entry path by filepath properties" do
|
49
|
+
post = FilepathPost.new
|
50
|
+
lambda { post.save }.should raise_error(ArgumentError, /isn't file to save/)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/model_spec.rb
CHANGED
@@ -1,33 +1,56 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
3
|
describe PlainRecord::Model do
|
4
|
-
|
4
|
+
|
5
|
+
after :each do
|
6
|
+
Post.loaded = { }
|
7
|
+
Author.loaded = { }
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should define virtual property" do
|
11
|
+
klass = Class.new do
|
12
|
+
include PlainRecord::Resource
|
13
|
+
virtual :one, Definers.none
|
14
|
+
end
|
15
|
+
|
16
|
+
klass.virtuals.should == [:one]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "shouldn't define virtual property without accessor from definers" do
|
20
|
+
lambda {
|
21
|
+
Class.new do
|
22
|
+
include PlainRecord::Resource
|
23
|
+
virtual :one, Definers.reader
|
24
|
+
end
|
25
|
+
}.should raise_error(ArgumentError, /own accessors/)
|
26
|
+
end
|
27
|
+
|
5
28
|
it "should define property" do
|
6
29
|
klass = Class.new do
|
7
30
|
include PlainRecord::Resource
|
8
31
|
property :one
|
9
32
|
end
|
10
|
-
|
33
|
+
|
11
34
|
klass.properties.should == [:one]
|
12
|
-
object = klass.new(nil, {'one' => 1})
|
35
|
+
object = klass.new(nil, { 'one' => 1 })
|
13
36
|
object.one.should == 1
|
14
37
|
object.one = 2
|
15
38
|
object.one.should == 2
|
16
39
|
end
|
17
|
-
|
40
|
+
|
18
41
|
it "should define text" do
|
19
42
|
klass = Class.new do
|
20
43
|
include PlainRecord::Resource
|
21
44
|
text :content
|
22
45
|
end
|
23
|
-
|
46
|
+
|
24
47
|
klass.texts.should == [:content]
|
25
|
-
object = klass.new(nil, {}, ['text'])
|
48
|
+
object = klass.new(nil, { }, ['text'])
|
26
49
|
object.content.should == 'text'
|
27
50
|
object.content = 'another'
|
28
51
|
object.content.should == 'another'
|
29
52
|
end
|
30
|
-
|
53
|
+
|
31
54
|
it "should call definer" do
|
32
55
|
klass = Class.new do
|
33
56
|
include PlainRecord::Resource
|
@@ -38,7 +61,7 @@ describe PlainRecord::Model do
|
|
38
61
|
end
|
39
62
|
klass.should has_methods(:one, :'one=', :'three=', :two)
|
40
63
|
end
|
41
|
-
|
64
|
+
|
42
65
|
it "should use accessors from definers" do
|
43
66
|
klass = Class.new do
|
44
67
|
include PlainRecord::Resource
|
@@ -47,25 +70,29 @@ describe PlainRecord::Model do
|
|
47
70
|
end
|
48
71
|
klass.should has_methods(:two)
|
49
72
|
end
|
50
|
-
|
51
|
-
it "should send property name to definer" do
|
73
|
+
|
74
|
+
it "should send property name and caller type to definer" do
|
52
75
|
definer = mock
|
53
|
-
definer.stub!(:
|
76
|
+
definer.stub!(:virtual).with(:one, :virtual)
|
77
|
+
definer.stub!(:property).with(:two, :property)
|
78
|
+
definer.stub!(:text).with(:three, :text)
|
54
79
|
klass = Class.new do
|
55
80
|
include PlainRecord::Resource
|
56
|
-
|
81
|
+
virtual :one, definer.method(:virtual)
|
82
|
+
property :two, definer.method(:property)
|
83
|
+
text :three, definer.method(:text)
|
57
84
|
end
|
58
85
|
end
|
59
|
-
|
86
|
+
|
60
87
|
it "should find all enrty files by glob pattern" do
|
61
88
|
klass = Class.new do
|
62
89
|
include PlainRecord::Resource
|
63
|
-
entry_in 'data/*/post.
|
90
|
+
entry_in 'data/*/post.md'
|
64
91
|
end
|
65
92
|
klass.storage.should == :entry
|
66
93
|
klass.files.sort.should == [FIRST, SECOND, THIRD]
|
67
94
|
end
|
68
|
-
|
95
|
+
|
69
96
|
it "should find all list files by glob pattern" do
|
70
97
|
klass = Class.new do
|
71
98
|
include PlainRecord::Resource
|
@@ -74,40 +101,40 @@ describe PlainRecord::Model do
|
|
74
101
|
klass.storage.should == :list
|
75
102
|
klass.files.sort.should == [EXTERN, INTERN]
|
76
103
|
end
|
77
|
-
|
104
|
+
|
78
105
|
it "should load YAML data from entry file" do
|
79
106
|
obj = Post.load_file(FIRST)
|
80
107
|
obj.should be_a(Post)
|
81
108
|
obj.title.should == 'First'
|
82
|
-
|
109
|
+
|
83
110
|
obj = Post.load_file(SECOND)
|
84
111
|
obj.should be_a(Post)
|
85
112
|
obj.title.should be_nil
|
86
113
|
end
|
87
|
-
|
114
|
+
|
88
115
|
it "should load text data from entry file" do
|
89
116
|
post = Post.load_file(FIRST)
|
90
117
|
post.summary.should == 'first --- content'
|
91
118
|
post.content.rstrip.should == "big\n---\ncontent"
|
92
|
-
|
119
|
+
|
93
120
|
post = Post.load_file(SECOND)
|
94
121
|
post.summary.rstrip.should == " only one"
|
95
122
|
post.content.should be_nil
|
96
123
|
end
|
97
|
-
|
124
|
+
|
98
125
|
it "should load data from list file" do
|
99
126
|
authors = Author.load_file(EXTERN)
|
100
127
|
authors.length.should == 2
|
101
|
-
|
128
|
+
|
102
129
|
authors[0].should be_a(Author)
|
103
130
|
authors[0].login.should be_nil
|
104
131
|
authors[0].name.should == 'Anonymous'
|
105
|
-
|
132
|
+
|
106
133
|
authors[1].should be_a(Author)
|
107
134
|
authors[1].login.should == 'super1997'
|
108
135
|
authors[1].name.should == 'SuperHacker'
|
109
136
|
end
|
110
|
-
|
137
|
+
|
111
138
|
it "shouldn't define text data in model with list storage" do
|
112
139
|
lambda {
|
113
140
|
klass = Class.new do
|
@@ -117,45 +144,79 @@ describe PlainRecord::Model do
|
|
117
144
|
end
|
118
145
|
}.should raise_error /entry_in/
|
119
146
|
end
|
120
|
-
|
147
|
+
|
121
148
|
it "should load all entries" do
|
122
|
-
Post.all.should
|
149
|
+
Post.all.should =~ [SECOND_POST, THIRD_POST, FIRST_POST]
|
123
150
|
end
|
124
|
-
|
151
|
+
|
125
152
|
it "should return entries by string matcher" do
|
126
153
|
Post.all(:title => 'First').should == [FIRST_POST]
|
127
154
|
end
|
128
|
-
|
155
|
+
|
129
156
|
it "should return entries by regexp matcher" do
|
130
157
|
Post.all(:title => /First/, :title => /Second/).should be_empty
|
131
158
|
end
|
132
|
-
|
159
|
+
|
133
160
|
it "should return entries by search proc" do
|
134
|
-
Post.all { |i| not i.title.nil? }.should
|
161
|
+
Post.all { |i| not i.title.nil? }.should =~ [THIRD_POST, FIRST_POST]
|
135
162
|
end
|
136
|
-
|
163
|
+
|
137
164
|
it "should return all list entries" do
|
138
|
-
Author.all.map { |i| i.login }.should
|
165
|
+
Author.all.map { |i| i.login }.should =~ [nil, 'super1997', 'john', 'ivan']
|
139
166
|
end
|
140
|
-
|
167
|
+
|
141
168
|
it "should return first entry" do
|
142
169
|
Post.first.should be_a(Post)
|
143
170
|
end
|
144
|
-
|
171
|
+
|
145
172
|
it "should return entry by string matcher" do
|
146
173
|
Post.first(:title => 'Third').should == THIRD_POST
|
147
174
|
end
|
148
|
-
|
175
|
+
|
149
176
|
it "should return entry by regexp matcher" do
|
150
|
-
Post.first(:title => /First
|
177
|
+
Post.first(:title => /First/).should == FIRST_POST
|
151
178
|
end
|
152
|
-
|
179
|
+
|
153
180
|
it "should return entry by search proc" do
|
154
181
|
Post.first { |i| false }.should be_nil
|
155
182
|
end
|
156
|
-
|
183
|
+
|
157
184
|
it "should return first list entry" do
|
158
|
-
Author.first { |i| not i.login.nil?
|
185
|
+
Author.first { |i| not i.login.nil? and i.type == 'extern' }.
|
186
|
+
name.should == 'SuperHacker'
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should delete file, cache and empty dirs" do
|
190
|
+
File.should_receive(:delete).with(FIRST)
|
191
|
+
|
192
|
+
first_dir = File.dirname(FIRST)
|
193
|
+
Dir.should_receive(:entries).with(first_dir).and_return(['.', '..'])
|
194
|
+
Dir.should_receive(:rmdir).with(first_dir)
|
195
|
+
Dir.should_receive(:entries).with(File.dirname(first_dir)).and_return(
|
196
|
+
['.', '..', '2', '3'])
|
197
|
+
|
198
|
+
Post.instance_eval { delete_file(FIRST) }
|
199
|
+
Post.loaded.should_not have_key(FIRST)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should move entry from one file to another" do
|
203
|
+
first = Post.first(:title => 'First')
|
204
|
+
Post.should_receive(:delete_file).with(FIRST)
|
205
|
+
Post.should_receive(:save_file).with(PlainRecord.root('file'))
|
206
|
+
first.file = 'file'
|
207
|
+
first.save
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should move list entry from one file to another" do
|
211
|
+
Author.should_receive(:save_file).with(INTERN).once
|
212
|
+
Author.should_receive(:save_file).with(PlainRecord.root('file')).twice
|
213
|
+
Author.should_receive(:delete_file).with(INTERN).once
|
214
|
+
|
215
|
+
authors = Author.all(:login => /john|ivan/)
|
216
|
+
authors.each do |author|
|
217
|
+
author.file = 'file'
|
218
|
+
author.save
|
219
|
+
end
|
159
220
|
end
|
160
|
-
|
221
|
+
|
161
222
|
end
|
data/spec/resource_spec.rb
CHANGED
@@ -1,30 +1,35 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
3
|
describe PlainRecord::Resource do
|
4
|
-
|
4
|
+
|
5
|
+
after :each do
|
6
|
+
Post.loaded = { }
|
7
|
+
Author.loaded = { }
|
8
|
+
end
|
9
|
+
|
5
10
|
it "should compare two object" do
|
6
|
-
first
|
7
|
-
|
8
|
-
second
|
9
|
-
|
10
|
-
first.should ==
|
11
|
+
first = Post.load_file(FIRST)
|
12
|
+
another = Post.load_file(FIRST)
|
13
|
+
second = Post.load_file(SECOND)
|
14
|
+
|
15
|
+
first.should == another
|
11
16
|
first.should_not == second
|
12
17
|
end
|
13
|
-
|
18
|
+
|
14
19
|
it "should remeber it file" do
|
15
20
|
Post.load_file(FIRST).file.should == FIRST
|
21
|
+
Post.load_file(FIRST).path.should == 'data/1/post.md'
|
16
22
|
end
|
17
|
-
|
23
|
+
|
18
24
|
it "should save entry" do
|
19
25
|
file = StringIO.new
|
20
26
|
File.should_receive(:open).with(FIRST, 'w').and_yield(file)
|
21
|
-
|
27
|
+
|
22
28
|
first = Post.first(:title => 'First')
|
23
|
-
first.title = 'First 1'
|
24
29
|
first.save
|
25
|
-
|
30
|
+
|
26
31
|
file.rewind
|
27
|
-
file.read.should == "title: First
|
32
|
+
file.read.should == "title: First\n" +
|
28
33
|
"---\n" +
|
29
34
|
"first --- content\n" +
|
30
35
|
"---\n" +
|
@@ -32,20 +37,76 @@ describe PlainRecord::Resource do
|
|
32
37
|
"---\n" +
|
33
38
|
"content\n"
|
34
39
|
end
|
35
|
-
|
36
|
-
it "should save
|
40
|
+
|
41
|
+
it "should save list entry" do
|
37
42
|
file = StringIO.new
|
43
|
+
Author.all
|
38
44
|
File.should_receive(:open).with(INTERN, 'w').and_yield(file)
|
39
|
-
|
45
|
+
|
40
46
|
john = Author.first(:login => 'john')
|
41
|
-
john.name = 'New name'
|
42
47
|
john.save
|
43
|
-
|
44
|
-
file.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
" name: Ivan Ivanov\n"
|
48
|
+
|
49
|
+
file.should has_yaml([
|
50
|
+
{ 'name' => 'John Smith', 'login' => 'john' },
|
51
|
+
{ 'name' => 'Ivan Ivanov', 'login' => 'ivan' }
|
52
|
+
])
|
49
53
|
end
|
50
|
-
|
54
|
+
|
55
|
+
it "should delete entry" do
|
56
|
+
Post.should_receive(:delete_file).with(FIRST)
|
57
|
+
Post.first(:title => 'First').destroy
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should save entry without file if model use only one file" do
|
61
|
+
class Model
|
62
|
+
include PlainRecord::Resource
|
63
|
+
list_in 'file.yml'
|
64
|
+
end
|
65
|
+
|
66
|
+
path = PlainRecord.root('file.yml')
|
67
|
+
File.should_receive(:open).with(path, 'w').and_yield(StringIO.new)
|
68
|
+
Model.new.save
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should delete list entry" do
|
72
|
+
file = StringIO.new
|
73
|
+
Author.all
|
74
|
+
File.should_receive(:open).with(INTERN, 'w').and_yield(file)
|
75
|
+
|
76
|
+
Author.first(:login => 'john').destroy
|
77
|
+
|
78
|
+
Author.first(:login => 'john').should be_nil
|
79
|
+
|
80
|
+
file.should has_yaml([{ 'name' => 'Ivan Ivanov', 'login' => 'ivan' }])
|
81
|
+
|
82
|
+
Author.should_receive(:delete_file).with(INTERN)
|
83
|
+
Author.first(:login => 'ivan').destroy
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should call callbacks" do
|
87
|
+
class Callbacked
|
88
|
+
include PlainRecord::Resource
|
89
|
+
entry_in 'data/*/post.md'
|
90
|
+
property :title
|
91
|
+
text :summary
|
92
|
+
text :content
|
93
|
+
end
|
94
|
+
|
95
|
+
callbacks = mock()
|
96
|
+
callbacks.should_receive(:path).
|
97
|
+
with(Callbacked.path, { :title => 'First' }).and_return('data/1/post.md')
|
98
|
+
callbacks.should_receive(:load).with(an_instance_of Callbacked)
|
99
|
+
callbacks.should_receive(:save).with(an_instance_of Callbacked).and_raise
|
100
|
+
callbacks.should_receive(:destroy).with(an_instance_of Callbacked).and_raise
|
101
|
+
|
102
|
+
Callbacked.after :path, &callbacks.method(:path)
|
103
|
+
Callbacked.before :load, &callbacks.method(:load)
|
104
|
+
Callbacked.before :save, &callbacks.method(:save)
|
105
|
+
Callbacked.before :destroy, &callbacks.method(:destroy)
|
106
|
+
|
107
|
+
first = Callbacked.first({ :title => 'First' })
|
108
|
+
lambda { first.save }.should raise_error
|
109
|
+
lambda { first.destroy }.should raise_error
|
110
|
+
end
|
111
|
+
|
51
112
|
end
|