plain_record 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe PlainRecord::Callbacks do
4
+ before :all do
5
+ module ::Fullname
6
+ include PlainRecord::Callbacks
7
+
8
+ def fullname(first, second)
9
+ use_callbacks(:fullname, first, second) do
10
+ first + ' ' + second
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ it "should use methods without callbacks" do
17
+ Class.new {
18
+ extend ::Fullname
19
+ }.fullname('John', 'Smith').should == 'John Smith'
20
+ end
21
+
22
+ it "should use before callbacks by priority" do
23
+ checker = mock()
24
+ checker.should_receive(:check_first).with('John', 'Smith').once.ordered
25
+ checker.should_receive(:check_last).with('John', 'Smith').once.ordered
26
+
27
+ Class.new {
28
+ extend ::Fullname
29
+
30
+ before :fullname, 2, &checker.method(:check_last)
31
+ before :fullname, 1, &checker.method(:check_first)
32
+ }.fullname('John', 'Smith').should == 'John Smith'
33
+ end
34
+
35
+ it "should use after callbacks by priority" do
36
+ adder = Class.new do
37
+ def self.add_first(full, first, last); full + ' ' + first.downcase end
38
+ def self.add_last(full, first, last); full + ' ' + last.downcase end
39
+ end
40
+
41
+ Class.new {
42
+ extend ::Fullname
43
+
44
+ after :fullname, 2, &adder.method(:add_last)
45
+ after :fullname, 1, &adder.method(:add_first)
46
+ }.fullname('John', 'Smith').should == 'John Smith john smith'
47
+ end
48
+
49
+ it "should set one callback for many events" do
50
+ klass = Class.new {
51
+ extend ::Fullname
52
+ before [:one, :two] do; end
53
+ before [:one, :two] do; end
54
+ }
55
+ klass.callbacks[:before].length.should == 2
56
+ klass.callbacks[:after].length.should == 2
57
+ end
58
+
59
+ end
@@ -0,0 +1,5 @@
1
+ - author_name: super1997
2
+ text: Cool!
3
+ answers:
4
+ - author_name: john
5
+ text: Thanks
File without changes
@@ -1,3 +1,3 @@
1
1
  unknow_property: 1
2
- ---
2
+ ---
3
3
  only one
@@ -0,0 +1,4 @@
1
+ title: Third
2
+ rate:
3
+ text: 2
4
+ subject: 5
@@ -1,3 +1,3 @@
1
1
  - name: Anonymous
2
- - login: super1997
3
- name: SuperHacker
2
+ - name: SuperHacker
3
+ login: super1997
@@ -1,4 +1,4 @@
1
- - login: john
2
- name: John Smith
3
- - login: ivan
4
- name: Ivan Ivanov
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!(:accessor).with(:one)
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
- property :one, definer.method(:accessor)
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.m'
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,58 +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 == [SECOND_POST, THIRD_POST, FIRST_POST]
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 == [THIRD_POST, FIRST_POST]
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 == [nil, 'super1997', 'john', 'ivan']
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|Third/).should == THIRD_POST
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? }.name.should == 'SuperHacker'
185
+ Author.first { |i| not i.login.nil? and i.type == 'extern' }.
186
+ name.should == 'SuperHacker'
159
187
  end
160
-
188
+
161
189
  it "should delete file, cache and empty dirs" do
162
190
  File.should_receive(:delete).with(FIRST)
163
-
191
+
164
192
  first_dir = File.dirname(FIRST)
165
193
  Dir.should_receive(:entries).with(first_dir).and_return(['.', '..'])
166
194
  Dir.should_receive(:rmdir).with(first_dir)
167
195
  Dir.should_receive(:entries).with(File.dirname(first_dir)).and_return(
168
196
  ['.', '..', '2', '3'])
169
-
197
+
170
198
  Post.instance_eval { delete_file(FIRST) }
171
199
  Post.loaded.should_not have_key(FIRST)
172
200
  end
173
-
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
220
+ end
221
+
174
222
  end
@@ -1,27 +1,33 @@
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 = Post.load_file(FIRST)
7
- another_first = Post.load_file(FIRST)
8
- second = Post.load_file(SECOND)
9
-
10
- first.should == another_first
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
29
  first.save
24
-
30
+
25
31
  file.rewind
26
32
  file.read.should == "title: First\n" +
27
33
  "---\n" +
@@ -31,39 +37,76 @@ describe PlainRecord::Resource do
31
37
  "---\n" +
32
38
  "content\n"
33
39
  end
34
-
40
+
35
41
  it "should save list entry" do
36
42
  file = StringIO.new
43
+ Author.all
37
44
  File.should_receive(:open).with(INTERN, 'w').and_yield(file)
38
-
45
+
39
46
  john = Author.first(:login => 'john')
40
47
  john.save
41
-
42
- file.rewind
43
- file.read.should == "- login: john\n" +
44
- " name: John Smith\n" +
45
- "- login: ivan\n" +
46
- " name: Ivan Ivanov\n"
48
+
49
+ file.should has_yaml([
50
+ { 'name' => 'John Smith', 'login' => 'john' },
51
+ { 'name' => 'Ivan Ivanov', 'login' => 'ivan' }
52
+ ])
47
53
  end
48
-
54
+
49
55
  it "should delete entry" do
50
56
  Post.should_receive(:delete_file).with(FIRST)
51
57
  Post.first(:title => 'First').destroy
52
58
  end
53
-
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
+
54
71
  it "should delete list entry" do
55
72
  file = StringIO.new
73
+ Author.all
56
74
  File.should_receive(:open).with(INTERN, 'w').and_yield(file)
57
-
75
+
58
76
  Author.first(:login => 'john').destroy
59
-
77
+
60
78
  Author.first(:login => 'john').should be_nil
61
- file.rewind
62
- file.read.should == "- login: ivan\n" +
63
- " name: Ivan Ivanov\n"
64
-
79
+
80
+ file.should has_yaml([{ 'name' => 'Ivan Ivanov', 'login' => 'ivan' }])
81
+
65
82
  Author.should_receive(:delete_file).with(INTERN)
66
83
  Author.first(:login => 'ivan').destroy
67
84
  end
68
-
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
+
69
112
  end
data/spec/spec_helper.rb CHANGED
@@ -2,43 +2,62 @@ require File.join(File.dirname(__FILE__), '../lib/plain_record')
2
2
 
3
3
  class Post
4
4
  include PlainRecord::Resource
5
-
6
- entry_in 'data/*/post.m'
7
-
5
+
6
+ entry_in 'data/*/post.md'
7
+
8
8
  property :title
9
9
  text :summary
10
10
  text :content
11
11
  end
12
12
 
13
+ class FilepathPost
14
+ include PlainRecord::Resource
15
+
16
+ entry_in 'data/**/*/post.md'
17
+
18
+ virtual :category, in_filepath(1)
19
+ virtual :name, in_filepath(2)
20
+
21
+ property :title
22
+ end
23
+
13
24
  class Author
14
25
  include PlainRecord::Resource
15
-
26
+
16
27
  list_in 'data/authors/*.yml'
17
-
28
+
29
+ virtual :type, in_filepath(1)
18
30
  property :login
19
31
  property :name
20
32
  end
21
33
 
22
34
  PlainRecord.root = File.dirname(__FILE__)
23
35
 
24
- FIRST = File.join(File.dirname(__FILE__), 'data/1/post.m')
25
- SECOND = File.join(File.dirname(__FILE__), 'data/2/post.m')
26
- THIRD = File.join(File.dirname(__FILE__), 'data/3/post.m')
27
- FIRST_POST = Post.load_file(FIRST)
36
+ FIRST = File.join(File.dirname(__FILE__), 'data/1/post.md')
37
+ SECOND = File.join(File.dirname(__FILE__), 'data/2/post.md')
38
+ THIRD = File.join(File.dirname(__FILE__), 'data/3/post.md')
39
+ FIRST_POST = Post.load_file(FIRST)
28
40
  SECOND_POST = Post.load_file(SECOND)
29
- THIRD_POST = Post.load_file(THIRD)
41
+ THIRD_POST = Post.load_file(THIRD)
30
42
 
31
43
  INTERN = File.join(File.dirname(__FILE__), 'data/authors/intern.yml')
32
44
  EXTERN = File.join(File.dirname(__FILE__), 'data/authors/extern.yml')
33
45
 
34
46
  def model_methods(model)
35
- model.instance_methods - Object.instance_methods -
36
- PlainRecord::Resource.instance_methods
47
+ (model.instance_methods - Object.instance_methods -
48
+ PlainRecord::Resource.instance_methods).map { |i| i.to_s }
37
49
  end
38
50
 
39
- Spec::Matchers.define :has_methods do |*methods|
51
+ RSpec::Matchers.define :has_methods do |*methods|
40
52
  match do |model|
41
- model_methods(model).sort == methods.sort
53
+ model_methods(model).sort == methods.map! { |i| i.to_s }.sort
54
+ end
55
+ end
56
+
57
+ RSpec::Matchers.define :has_yaml do |data|
58
+ match do |file|
59
+ file.rewind
60
+ YAML.load(file.read).should == data
42
61
  end
43
62
  end
44
63