plain_record 0.1.0 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,146 @@
|
|
1
|
+
=begin
|
2
|
+
Module to add before/after hooks.
|
3
|
+
|
4
|
+
Copyright (C) 2009 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU Lesser General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module PlainRecord
|
21
|
+
# Callbacks are hooks that allow you to define methods to run before and
|
22
|
+
# after some method, to change it logic.
|
23
|
+
module Callbacks
|
24
|
+
# Hash of class callbacks with property.
|
25
|
+
attr_accessor :callbacks
|
26
|
+
|
27
|
+
# Set block as callback before +events+. Callback with less +priority+ will
|
28
|
+
# start earlier.
|
29
|
+
#
|
30
|
+
# class File
|
31
|
+
# include PlainRecord::Callbacks
|
32
|
+
#
|
33
|
+
# attr_accessor :name
|
34
|
+
# attr_accessor :content
|
35
|
+
#
|
36
|
+
# def save
|
37
|
+
# use_callbacks(:save, self) do
|
38
|
+
# File.open(@name, 'w') { |io| io.puts @content }
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# class NewFile < File
|
44
|
+
# before :save do |file|
|
45
|
+
# while File.exists? file.name
|
46
|
+
# file.name = 'another ' + file.name
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# before, :save do
|
51
|
+
# raise ArgumentError if 255 < @name.length
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
def before(events, priority = 1, &block)
|
55
|
+
Array(events).each do |event|
|
56
|
+
add_callback(:before, event, priority, block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set block as callback after +events+. Callback with less +priority+ will
|
61
|
+
# start earlier.
|
62
|
+
#
|
63
|
+
# After callbacks may change method return, which will be pass as first
|
64
|
+
# argument for first callback. It return will be pass for next callback and
|
65
|
+
# so on.
|
66
|
+
#
|
67
|
+
# class Person
|
68
|
+
# include PlainRecord::Callbacks
|
69
|
+
#
|
70
|
+
# def name
|
71
|
+
# use_callbacks(:name) do
|
72
|
+
# 'John'
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# class GreatPerson < Person
|
78
|
+
# after :name, 2 do |name|
|
79
|
+
# 'Great ' + name
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# after :name do |name|
|
83
|
+
# 'The ' + name
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# GreatPerson.new.name #=> "The Great John"
|
88
|
+
def after(events, priority = 1, &block)
|
89
|
+
Array(events).each do |event|
|
90
|
+
add_callback(:after, event, priority, block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Call +before+ callbacks for +event+ with +params+. In your
|
95
|
+
# code use more pretty +use_callbacks+ method.
|
96
|
+
def call_before_callbacks(event, params)
|
97
|
+
init_callbacks(event)
|
98
|
+
@callbacks[:before][event].each do |before, priority|
|
99
|
+
before.call(*params)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Call +before+ callbacks for +event+ with +params+. Callbacks can change
|
104
|
+
# +result+. In your code use more pretty +use_callbacks+ method.
|
105
|
+
def call_after_callbacks(event, result, params)
|
106
|
+
init_callbacks(event)
|
107
|
+
@callbacks[:after][event].each do |after, priority|
|
108
|
+
result = after.call(result, *params)
|
109
|
+
end
|
110
|
+
result
|
111
|
+
end
|
112
|
+
|
113
|
+
# Call before callback for +event+, run block and give it result to
|
114
|
+
# after callbacks.
|
115
|
+
#
|
116
|
+
# def my_save_method(entry)
|
117
|
+
# use_callbacks(:save, enrty) do
|
118
|
+
# entry.file.write
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
def use_callbacks(event, *params, &block)
|
122
|
+
call_before_callbacks(event, params)
|
123
|
+
result = yield
|
124
|
+
call_after_callbacks(event, result, params)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# Backend for +before+ and +after+ method to add callback.
|
130
|
+
def add_callback(type, event, priority, block)
|
131
|
+
init_callbacks(event)
|
132
|
+
|
133
|
+
@callbacks[type][event] << [block, priority]
|
134
|
+
@callbacks[type][event].sort! { |a, b| a[1] <=> b[1] }
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check and create Hash into +callbacks+ for +event+ if necessary.
|
138
|
+
def init_callbacks(event)
|
139
|
+
unless @callbacks
|
140
|
+
@callbacks = { :before => { }, :after => { } }
|
141
|
+
end
|
142
|
+
@callbacks[:before][event] = [] unless @callbacks[:before][event]
|
143
|
+
@callbacks[:after][event] = [] unless @callbacks[:after][event]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
=begin
|
2
|
+
Extention to get property from entry file path.
|
3
|
+
|
4
|
+
Copyright (C) 2009 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU Lesser General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module PlainRecord
|
21
|
+
# Extention to get properties from enrty file path. For example, your blog
|
22
|
+
# post may stored in <tt>_name_/post.md</tt>, and post model will have +name+
|
23
|
+
# property. Also if you set name property to Model#first or Model#all method,
|
24
|
+
# they will load entry directly only by it file.
|
25
|
+
#
|
26
|
+
# To define filepath property:
|
27
|
+
# 1. Use <tt>*</tt> or <tt>**</tt> pattern in model path in +enrty_in+ or
|
28
|
+
# +list_in+.
|
29
|
+
# 2. In +virtual+ method use <tt>in_filepath(i)</tt> definer after name with
|
30
|
+
# <tt>*</tt> or <tt>**</tt> number (start from 1).
|
31
|
+
#
|
32
|
+
# Define filepath property only after +entry_in+ or +list_in+ call.
|
33
|
+
#
|
34
|
+
# class Post
|
35
|
+
# include PlainRecord::Resource
|
36
|
+
#
|
37
|
+
# entry_in '*/*/post.md'
|
38
|
+
#
|
39
|
+
# virtual :category, in_filepath(1)
|
40
|
+
# virtual :name, in_filepath(1)
|
41
|
+
# …
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# superpost = Post.new
|
45
|
+
# superpost.name = 'superpost'
|
46
|
+
# superpost.category = 'best/'
|
47
|
+
# superpost.save # Save to best/superpost/post.md
|
48
|
+
#
|
49
|
+
# bests = Post.all(category: 'best') # Look up only in best/ dir
|
50
|
+
module Filepath
|
51
|
+
attr_accessor :filepath_properties
|
52
|
+
attr_accessor :filepath_regexp
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Return definer for filepath property for +number+ <tt>*</tt> or
|
57
|
+
# <tt>**</tt> pattern in path.
|
58
|
+
def in_filepath(number)
|
59
|
+
proc do |property, caller|
|
60
|
+
if :virtual != caller
|
61
|
+
raise ArgumentError, "You must create filepath property #{property}" +
|
62
|
+
' virtual creator'
|
63
|
+
end
|
64
|
+
Filepath.define_property(self, property, number)
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
# Define class variables and events in +klass+. It should be call once on
|
71
|
+
# same class after +entry_in+ or +list_in+ call.
|
72
|
+
def install(klass)
|
73
|
+
klass.filepath_properties = { }
|
74
|
+
|
75
|
+
path = Regexp.escape(klass.path).gsub(/\\\*\\\*(\/|$)/, '(.*)').
|
76
|
+
gsub('\\*', '([^/]+)')
|
77
|
+
klass.filepath_regexp = Regexp.new(path)
|
78
|
+
|
79
|
+
klass.class_eval do
|
80
|
+
attr_accessor :filepath_data
|
81
|
+
end
|
82
|
+
|
83
|
+
klass.after :load do |result, entry|
|
84
|
+
if entry.path
|
85
|
+
data = klass.filepath_regexp.match(entry.path)
|
86
|
+
entry.filepath_data = { }
|
87
|
+
klass.filepath_properties.each_pair do |number, name|
|
88
|
+
entry.filepath_data[name] = data[number]
|
89
|
+
end
|
90
|
+
else
|
91
|
+
entry.filepath_data = { }
|
92
|
+
klass.filepath_properties.each_value do |name|
|
93
|
+
entry.filepath_data[name] = entry.data[name]
|
94
|
+
entry.data.delete(name)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
klass.after :path do |path, matchers|
|
101
|
+
i = 0
|
102
|
+
path.gsub /(\*\*(\/|$)|\*)/ do |pattern|
|
103
|
+
i += 1
|
104
|
+
property = klass.filepath_properties[i]
|
105
|
+
unless matchers[property].is_a? Regexp or matchers[property].nil?
|
106
|
+
matchers[property]
|
107
|
+
else
|
108
|
+
pattern
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
klass.before :save do |entry|
|
114
|
+
unless entry.file
|
115
|
+
path = klass.path(entry.filepath_data)
|
116
|
+
entry.file = path unless path =~ /[\*\[\?\{]/
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Define in +klass+ filepath property with +name+ for +number+ <tt>*</tt>
|
122
|
+
# or <tt>**</tt> pattern in path.
|
123
|
+
def define_property(klass, name, number)
|
124
|
+
unless klass.filepath_properties
|
125
|
+
install(klass)
|
126
|
+
end
|
127
|
+
|
128
|
+
klass.filepath_properties[number] = name
|
129
|
+
|
130
|
+
klass.class_eval <<-EOS, __FILE__, __LINE__
|
131
|
+
def #{name}
|
132
|
+
@filepath_data[:#{name}]
|
133
|
+
end
|
134
|
+
def #{name}=(value)
|
135
|
+
@filepath_data[:#{name}] = value
|
136
|
+
end
|
137
|
+
EOS
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/plain_record/model.rb
CHANGED
@@ -26,31 +26,55 @@ module PlainRecord
|
|
26
26
|
dir = Pathname(__FILE__).dirname.expand_path + 'model'
|
27
27
|
autoload :Entry, (dir + 'entry').to_s
|
28
28
|
autoload :List, (dir + 'list').to_s
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
|
30
|
+
include PlainRecord::Callbacks
|
31
|
+
include PlainRecord::Filepath
|
32
|
+
include PlainRecord::Associations
|
33
|
+
|
34
|
+
# YAML properties names.
|
35
|
+
attr_accessor :properties
|
36
|
+
|
33
37
|
# Name of special properties with big text.
|
34
|
-
|
35
|
-
|
38
|
+
attr_accessor :texts
|
39
|
+
|
40
|
+
# Properties names with dynamic value.
|
41
|
+
attr_accessor :virtuals
|
42
|
+
|
36
43
|
# Storage type: +:entry+ or +:list+.
|
37
44
|
attr_reader :storage
|
38
|
-
|
45
|
+
|
39
46
|
# Content of already loaded files.
|
40
|
-
|
41
|
-
|
47
|
+
attr_accessor :loaded
|
48
|
+
|
49
|
+
def self.extended(base) #:nodoc:
|
50
|
+
base.properties = []
|
51
|
+
base.virtuals = []
|
52
|
+
base.texts = []
|
53
|
+
base.loaded = { }
|
54
|
+
end
|
55
|
+
|
42
56
|
# Load and return all entries in +file+.
|
43
57
|
#
|
44
58
|
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
45
59
|
def load_file(file); end
|
46
|
-
|
47
|
-
# Call block on all entry
|
48
|
-
# loading, so it is useful if you planing
|
49
|
-
# the middle (for example, like +first+).
|
60
|
+
|
61
|
+
# Call block on all entry, which is may be match for +matchers+. Unlike
|
62
|
+
# <tt>all.each</tt> it use lazy file loading, so it is useful if you planing
|
63
|
+
# to break this loop somewhere in the middle (for example, like +first+).
|
64
|
+
#
|
65
|
+
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
66
|
+
def each_entry(matchers = { }); end
|
67
|
+
|
68
|
+
# Delete +entry+ from +file+.
|
69
|
+
#
|
70
|
+
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
71
|
+
def delete_entry(file, entry = nil); end
|
72
|
+
|
73
|
+
# Move +entry+ from one file to another.
|
50
74
|
#
|
51
75
|
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
52
|
-
def
|
53
|
-
|
76
|
+
def move_entry(entry, from, to); end
|
77
|
+
|
54
78
|
# Write all loaded entries to +file+.
|
55
79
|
def save_file(file)
|
56
80
|
if @loaded.has_key? file
|
@@ -59,7 +83,7 @@ module PlainRecord
|
|
59
83
|
end
|
60
84
|
end
|
61
85
|
end
|
62
|
-
|
86
|
+
|
63
87
|
# Return all entries, which is match for +matchers+ and return true on
|
64
88
|
# +block+.
|
65
89
|
#
|
@@ -69,13 +93,13 @@ module PlainRecord
|
|
69
93
|
# Post.all(title: 'Post title')
|
70
94
|
# Post.all(title: /^Post/, summary: /cool/)
|
71
95
|
# Post.all { |post| 20 < Post.content.length }
|
72
|
-
def all(matchers = {}, &block)
|
73
|
-
entries = all_entries
|
96
|
+
def all(matchers = { }, &block)
|
97
|
+
entries = all_entries(matchers)
|
74
98
|
entries.delete_if { |i| not match(i, matchers) } if matchers
|
75
|
-
entries.delete_if { |i| not block.call(i) }
|
99
|
+
entries.delete_if { |i| not block.call(i) } if block_given?
|
76
100
|
entries
|
77
101
|
end
|
78
|
-
|
102
|
+
|
79
103
|
# Return first entry, which is match for +matchers+ and return true on
|
80
104
|
# +block+.
|
81
105
|
#
|
@@ -85,11 +109,13 @@ module PlainRecord
|
|
85
109
|
# Post.first(title: 'Post title')
|
86
110
|
# Post.first(title: /^Post/, summary: /cool/)
|
87
111
|
# Post.first { |post| 2 < Post.title.length }
|
88
|
-
def first(matchers = {}, &block)
|
112
|
+
def first(matchers = { }, &block)
|
89
113
|
if matchers and block_given?
|
90
|
-
each_entry
|
114
|
+
each_entry(matchers) do |i|
|
115
|
+
return i if match(i, matchers) and block.call(i)
|
116
|
+
end
|
91
117
|
elsif matchers
|
92
|
-
each_entry { |i| return i if match(i, matchers) }
|
118
|
+
each_entry(matchers) { |i| return i if match(i, matchers) }
|
93
119
|
elsif block_given?
|
94
120
|
each_entry { |i| return i if block.call(i) }
|
95
121
|
else
|
@@ -97,24 +123,45 @@ module PlainRecord
|
|
97
123
|
end
|
98
124
|
nil
|
99
125
|
end
|
100
|
-
|
101
|
-
# Return all
|
102
|
-
def files
|
103
|
-
Dir.glob(
|
126
|
+
|
127
|
+
# Return all file list for models, which match for +matchers+.
|
128
|
+
def files(matchers = { })
|
129
|
+
Dir.glob(PlainRecord.root(path(matchers)))
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return glob pattern to for files with entris, which is may be match for
|
133
|
+
# +matchers+.
|
134
|
+
def path(matchers = { })
|
135
|
+
use_callbacks(:path, matchers) do
|
136
|
+
@path
|
137
|
+
end
|
104
138
|
end
|
105
|
-
|
139
|
+
|
106
140
|
private
|
107
|
-
|
108
|
-
# Return all model entries
|
141
|
+
|
142
|
+
# Return all model entries, which is may be match for +matchers+.
|
109
143
|
#
|
110
144
|
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
111
|
-
def all_entries; end
|
112
|
-
|
145
|
+
def all_entries(matchers); end
|
146
|
+
|
113
147
|
# Return string representation of +entries+ to write it to file.
|
114
148
|
#
|
115
149
|
# See method code in <tt>Model::Entry</tt> or <tt>Model::List</tt>.
|
116
150
|
def entries_string(entries); end
|
117
|
-
|
151
|
+
|
152
|
+
# Delete file, cache and empty dirs in path.
|
153
|
+
def delete_file(file)
|
154
|
+
File.delete(file)
|
155
|
+
@loaded.delete(file)
|
156
|
+
|
157
|
+
path = Pathname(file).dirname
|
158
|
+
root = Pathname(PlainRecord.root)
|
159
|
+
until 2 != path.entries.length or path == root
|
160
|
+
path.rmdir
|
161
|
+
path = path.parent
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
118
165
|
# Match +object+ by +matchers+ to use in +all+ and +first+ methods.
|
119
166
|
def match(object, matchers)
|
120
167
|
matchers.each_pair do |key, matcher|
|
@@ -127,20 +174,19 @@ module PlainRecord
|
|
127
174
|
end
|
128
175
|
true
|
129
176
|
end
|
130
|
-
|
177
|
+
|
131
178
|
# Set glob +pattern+ for files with entry. Each file must contain one entry.
|
132
179
|
# To set root for this path use +PlainRecord.root+.
|
133
180
|
#
|
134
181
|
# Also add methods from <tt>Model::Entry</tt>.
|
135
182
|
#
|
136
|
-
# entry_in 'content/*/post.
|
183
|
+
# entry_in 'content/*/post.md'
|
137
184
|
def entry_in(path)
|
138
185
|
@storage = :entry
|
139
186
|
@path = path
|
140
187
|
self.extend PlainRecord::Model::Entry
|
141
|
-
@loaded = {}
|
142
188
|
end
|
143
|
-
|
189
|
+
|
144
190
|
# Set glob +pattern+ for files with list of entries. Each file may contain
|
145
191
|
# several entries, but you may have several files. All data will storage
|
146
192
|
# in YAML, so you can’t define +text+.
|
@@ -152,29 +198,55 @@ module PlainRecord
|
|
152
198
|
@storage = :list
|
153
199
|
@path = path
|
154
200
|
self.extend PlainRecord::Model::List
|
155
|
-
@loaded = {}
|
156
201
|
end
|
157
|
-
|
158
|
-
# Add property
|
202
|
+
|
203
|
+
# Add virtual property with some +name+ to model. It value willn’t be in
|
204
|
+
# file and will be calculated dynamically.
|
205
|
+
#
|
206
|
+
# You _must_ provide your own define logic by +definers+. Definer Proc
|
207
|
+
# will be call with property name in first argument and may return
|
208
|
+
# +:accessor+, +:writer+ or +:reader+ this method create standard methods
|
209
|
+
# to access to property.
|
210
|
+
#
|
211
|
+
# class Post
|
212
|
+
# include PlainRecord::Resource
|
213
|
+
#
|
214
|
+
# entry_in 'posts/*/post.md'
|
215
|
+
#
|
216
|
+
# virtual :name, in_filepath(1)
|
217
|
+
# end
|
218
|
+
def virtual(name, *definers)
|
219
|
+
@virtuals ||= []
|
220
|
+
@virtuals << name
|
221
|
+
|
222
|
+
accessors = call_definers(definers, name, :virtual)
|
223
|
+
|
224
|
+
if accessors[:reader] or accessors[:writer]
|
225
|
+
raise ArgumentError, 'You must provide you own accessors for virtual ' +
|
226
|
+
"property #{name}"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Add property with some +name+ to model. It will be stored as YAML.
|
159
231
|
#
|
160
232
|
# You can provide your own define logic by +definers+. Definer Proc
|
161
233
|
# will be call with property name in first argument and may return
|
162
234
|
# +:accessor+, +:writer+ or +:reader+ this method create standard methods
|
163
235
|
# to access to property.
|
164
|
-
#
|
236
|
+
#
|
165
237
|
# class Post
|
166
238
|
# include PlainRecord::Resource
|
167
239
|
#
|
168
|
-
# entry_in 'posts/*/post.
|
240
|
+
# entry_in 'posts/*/post.md'
|
169
241
|
#
|
170
242
|
# property :title
|
171
243
|
# end
|
172
244
|
def property(name, *definers)
|
173
245
|
@properties ||= []
|
174
246
|
@properties << name
|
175
|
-
|
176
|
-
accessors = call_definers(definers, name)
|
177
|
-
|
247
|
+
|
248
|
+
accessors = call_definers(definers, name, :property)
|
249
|
+
|
178
250
|
if accessors[:reader]
|
179
251
|
class_eval <<-EOS, __FILE__, __LINE__
|
180
252
|
def #{name}
|
@@ -190,7 +262,7 @@ module PlainRecord
|
|
190
262
|
EOS
|
191
263
|
end
|
192
264
|
end
|
193
|
-
|
265
|
+
|
194
266
|
# Add special property with big text (for example, blog entry content). It
|
195
267
|
# will stored after 3 dashes (<tt>---</tt>).
|
196
268
|
#
|
@@ -205,19 +277,19 @@ module PlainRecord
|
|
205
277
|
# == Example
|
206
278
|
#
|
207
279
|
# Model:
|
208
|
-
#
|
280
|
+
#
|
209
281
|
# class Post
|
210
282
|
# include PlainRecord::Resource
|
211
283
|
#
|
212
|
-
# entry_in 'posts/*/post.
|
284
|
+
# entry_in 'posts/*/post.md'
|
213
285
|
#
|
214
286
|
# property :title
|
215
287
|
# text :summary
|
216
288
|
# text :content
|
217
289
|
# end
|
218
|
-
#
|
290
|
+
#
|
219
291
|
# File:
|
220
|
-
#
|
292
|
+
#
|
221
293
|
# title: Post title
|
222
294
|
# ---
|
223
295
|
# Post summary
|
@@ -227,13 +299,13 @@ module PlainRecord
|
|
227
299
|
if :list == @storage
|
228
300
|
raise ArgumentError, 'Text is supported by only entry_in models'
|
229
301
|
end
|
230
|
-
|
302
|
+
|
231
303
|
@texts ||= []
|
232
304
|
@texts << name
|
233
305
|
number = @texts.length - 1
|
234
|
-
|
235
|
-
accessors = call_definers(definers, name)
|
236
|
-
|
306
|
+
|
307
|
+
accessors = call_definers(definers, name, :text)
|
308
|
+
|
237
309
|
if accessors[:reader]
|
238
310
|
class_eval <<-EOS, __FILE__, __LINE__
|
239
311
|
def #{name}
|
@@ -249,14 +321,15 @@ module PlainRecord
|
|
249
321
|
EOS
|
250
322
|
end
|
251
323
|
end
|
252
|
-
|
253
|
-
# Call +definers+
|
324
|
+
|
325
|
+
# Call +definers+ from +caller+ (<tt>:virtual</tt>, <tt>:property</tt> or
|
326
|
+
# <tt>:text</tt>) for property with +name+ and return accessors, which will
|
254
327
|
# be created as standart by +property+ or +text+ method.
|
255
|
-
def call_definers(definers, name)
|
256
|
-
accessors = {:reader => true, :writer => true}
|
257
|
-
|
328
|
+
def call_definers(definers, name, caller)
|
329
|
+
accessors = { :reader => true, :writer => true }
|
330
|
+
|
258
331
|
definers.each do |definer|
|
259
|
-
access = definer.call(name)
|
332
|
+
access = definer.call(name, caller)
|
260
333
|
if :writer == access or access.nil?
|
261
334
|
accessors[:reader] = false
|
262
335
|
end
|
@@ -264,7 +337,7 @@ module PlainRecord
|
|
264
337
|
accessors[:writer] = false
|
265
338
|
end
|
266
339
|
end
|
267
|
-
|
340
|
+
|
268
341
|
accessors
|
269
342
|
end
|
270
343
|
end
|