runo 0.2.1 → 0.2.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.
Files changed (151) hide show
  1. data/README.rdoc +1 -118
  2. data/bin/runo +4 -29
  3. data/lib/dummy.rb +0 -0
  4. metadata +12 -278
  5. data/lib/_error.rb +0 -14
  6. data/lib/_field.rb +0 -260
  7. data/lib/_i18n.rb +0 -144
  8. data/lib/_parser.rb +0 -256
  9. data/lib/_path.rb +0 -86
  10. data/lib/_storage/_storage.rb +0 -215
  11. data/lib/_storage/file.rb +0 -201
  12. data/lib/_storage/sequel.rb +0 -174
  13. data/lib/_storage/temp.rb +0 -73
  14. data/lib/_widget/action_create.rb +0 -23
  15. data/lib/_widget/action_login.rb +0 -22
  16. data/lib/_widget/action_signup.rb +0 -16
  17. data/lib/_widget/action_update.rb +0 -16
  18. data/lib/_widget/crumb.rb +0 -24
  19. data/lib/_widget/done.rb +0 -16
  20. data/lib/_widget/login.rb +0 -25
  21. data/lib/_widget/me.rb +0 -31
  22. data/lib/_widget/message.rb +0 -51
  23. data/lib/_widget/navi.rb +0 -88
  24. data/lib/_widget/submit.rb +0 -49
  25. data/lib/_widget/view_ym.rb +0 -77
  26. data/lib/_workflow/_workflow.rb +0 -89
  27. data/lib/_workflow/attachment.rb +0 -50
  28. data/lib/_workflow/blog.rb +0 -28
  29. data/lib/_workflow/contact.rb +0 -23
  30. data/lib/_workflow/forum.rb +0 -26
  31. data/lib/_workflow/register.rb +0 -39
  32. data/lib/meta/_meta.rb +0 -20
  33. data/lib/meta/group.rb +0 -19
  34. data/lib/meta/id.rb +0 -59
  35. data/lib/meta/owner.rb +0 -21
  36. data/lib/meta/timestamp.rb +0 -118
  37. data/lib/runo.rb +0 -396
  38. data/lib/scalar/checkbox.rb +0 -68
  39. data/lib/scalar/file.rb +0 -144
  40. data/lib/scalar/img.rb +0 -112
  41. data/lib/scalar/password.rb +0 -58
  42. data/lib/scalar/radio.rb +0 -47
  43. data/lib/scalar/select.rb +0 -47
  44. data/lib/scalar/text.rb +0 -38
  45. data/lib/scalar/textarea.rb +0 -35
  46. data/lib/scalar/textarea_pre.rb +0 -14
  47. data/lib/scalar/textarea_wiki.rb +0 -173
  48. data/lib/set/_set.rb +0 -196
  49. data/lib/set/dynamic.rb +0 -177
  50. data/lib/set/static.rb +0 -102
  51. data/lib/set/static_folder.rb +0 -96
  52. data/locale/en/index.po +0 -242
  53. data/locale/index.pot +0 -243
  54. data/locale/ja/index.po +0 -242
  55. data/locale/lazy_parser.rb +0 -54
  56. data/skel/config.ru +0 -27
  57. data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
  58. data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
  59. data/skel/skin/_users/00000000_frank.yaml +0 -12
  60. data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
  61. data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
  62. data/skel/skin/_users/00000000_root.yaml +0 -11
  63. data/skel/skin/_users/css/users.css +0 -21
  64. data/skel/skin/_users/css/users.less +0 -25
  65. data/skel/skin/_users/done.html +0 -42
  66. data/skel/skin/_users/index.html +0 -46
  67. data/skel/skin/_users/index.yaml +0 -3
  68. data/skel/skin/_users/summary.html +0 -40
  69. data/skel/skin/css/base.css +0 -93
  70. data/skel/skin/css/base.less +0 -139
  71. data/skel/skin/css/coax.css +0 -199
  72. data/skel/skin/css/coax.less +0 -244
  73. data/skel/skin/examples/blog/20091214_0001.yaml +0 -8
  74. data/skel/skin/examples/blog/20100630_0001.yaml +0 -8
  75. data/skel/skin/examples/blog/20100630_0002.yaml +0 -14
  76. data/skel/skin/examples/blog/20100701_0001.yaml +0 -8
  77. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
  78. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
  79. data/skel/skin/examples/blog/20100701_0002.yaml +0 -19
  80. data/skel/skin/examples/blog/frank/20100701_0001.yaml +0 -10
  81. data/skel/skin/examples/blog/frank/index.yaml +0 -4
  82. data/skel/skin/examples/blog/index.html +0 -51
  83. data/skel/skin/examples/blog/rss.xml +0 -18
  84. data/skel/skin/examples/contact/20100701_0001-file.txt +0 -1
  85. data/skel/skin/examples/contact/20100701_0001.yaml +0 -15
  86. data/skel/skin/examples/contact/20100701_0002.yaml +0 -8
  87. data/skel/skin/examples/contact/20100701_0003.yaml +0 -9
  88. data/skel/skin/examples/contact/index.html +0 -47
  89. data/skel/skin/examples/contact/js/contact.js +0 -13
  90. data/skel/skin/examples/contact/summary.html +0 -54
  91. data/skel/skin/examples/forum/20100701_0001.yaml +0 -41
  92. data/skel/skin/examples/forum/20100701_0002.yaml +0 -25
  93. data/skel/skin/examples/forum/index.html +0 -68
  94. data/skel/skin/examples/forum/summary.html +0 -47
  95. data/skel/skin/examples/index.html +0 -73
  96. data/skel/skin/index.html +0 -39
  97. data/skel/skin/js/base.js +0 -50
  98. data/t/locale/de/index.po +0 -19
  99. data/t/locale/en-GB/index.po +0 -25
  100. data/t/locale/ja/index.po +0 -30
  101. data/t/skin/_users/00000000_test.yaml +0 -3
  102. data/t/skin/_users/index.html +0 -13
  103. data/t/skin/foo/20091120_0001.yaml +0 -7
  104. data/t/skin/foo/bar/20091120_0001.yaml +0 -5
  105. data/t/skin/foo/bar/index.yaml +0 -5
  106. data/t/skin/foo/baz/css/baz.css +0 -1
  107. data/t/skin/foo/css/foo.css +0 -1
  108. data/t/skin/foo/index.html +0 -14
  109. data/t/skin/foo/index.yaml +0 -7
  110. data/t/skin/foo/not_css/foo.css +0 -1
  111. data/t/skin/foo/qux/index.html +0 -8
  112. data/t/skin/foo/qux/moo/index.html +0 -6
  113. data/t/skin/foo/sub-20100306_0001.yaml +0 -3
  114. data/t/skin/index.yaml +0 -3
  115. data/t/skin/t_attachment/index.html +0 -13
  116. data/t/skin/t_contact/done.html +0 -6
  117. data/t/skin/t_contact/index.html +0 -9
  118. data/t/skin/t_file/index.html +0 -16
  119. data/t/skin/t_img/index.html +0 -14
  120. data/t/skin/t_img/test.jpg +0 -0
  121. data/t/skin/t_select/index.html +0 -9
  122. data/t/skin/t_store/index.html +0 -9
  123. data/t/skin/t_summary/20100326_0001.yaml +0 -3
  124. data/t/skin/t_summary/create.html +0 -9
  125. data/t/skin/t_summary/index.html +0 -9
  126. data/t/skin/t_summary/summary.html +0 -9
  127. data/t/t.rb +0 -27
  128. data/t/test_checkbox.rb +0 -273
  129. data/t/test_field.rb +0 -330
  130. data/t/test_file.rb +0 -900
  131. data/t/test_id.rb +0 -215
  132. data/t/test_img.rb +0 -328
  133. data/t/test_meta.rb +0 -57
  134. data/t/test_parser.rb +0 -1516
  135. data/t/test_password.rb +0 -188
  136. data/t/test_radio.rb +0 -226
  137. data/t/test_role.rb +0 -249
  138. data/t/test_runo.rb +0 -768
  139. data/t/test_runo_call.rb +0 -1281
  140. data/t/test_runo_i18n.rb +0 -325
  141. data/t/test_select.rb +0 -182
  142. data/t/test_set_complex.rb +0 -527
  143. data/t/test_set_dynamic.rb +0 -1504
  144. data/t/test_set_folder.rb +0 -515
  145. data/t/test_set_permit.rb +0 -246
  146. data/t/test_set_static.rb +0 -468
  147. data/t/test_storage.rb +0 -915
  148. data/t/test_text.rb +0 -125
  149. data/t/test_textarea.rb +0 -138
  150. data/t/test_timestamp.rb +0 -473
  151. data/t/test_workflow.rb +0 -367
@@ -1,86 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- module Runo::Path
7
-
8
- module_function
9
-
10
- def tid_of(path)
11
- path[Runo::REX::TID]
12
- end
13
-
14
- def steps_of(path)
15
- _dirname(path).gsub(Runo::REX::PATH_ID, '').split('/').select {|step_or_cond|
16
- step_or_cond != '' &&
17
- step_or_cond !~ Regexp.union(Runo::REX::COND, Runo::REX::COND_D, Runo::REX::TID)
18
- }
19
- end
20
-
21
- def base_of(path)
22
- base = Runo::Set::Static::Folder.root.item steps_of(path)
23
- if base.is_a? Runo::Set::Static::Folder
24
- base.item('main') || base.find {|item| item.is_a? Runo::Set::Dynamic } || base
25
- else
26
- base
27
- end
28
- end
29
-
30
- def conds_of(path)
31
- dir = _dirname path.gsub(Runo::REX::PATH_ID, '')
32
- conds = $& ? {:id => sprintf('%.8d_%.4d', $1, $2)} : {}
33
-
34
- dir.split('/').inject(conds) {|conds, step_or_cond|
35
- if step_or_cond =~ Runo::REX::COND
36
- conds[$1.intern] = $2
37
- elsif step_or_cond =~ Runo::REX::COND_D
38
- conds[:d] = $&
39
- end
40
- conds
41
- }
42
- end
43
-
44
- def action_of(path)
45
- a = _basename(path).to_s[/^[a-z]+/]
46
- a.intern if a && a != 'index'
47
- end
48
-
49
- def sub_action_of(path)
50
- a = _basename(path).to_s[/_([a-z]+)/, 1]
51
- a.intern if a
52
- end
53
-
54
- def path_of(conds)
55
- conds = {} unless conds.is_a? ::Hash
56
- (
57
- (conds.keys - [:order, :p, :id]) |
58
- ([:order, :p, :id] & conds.keys)
59
- ).collect {|cid|
60
- if cid == :id
61
- ids = Array(conds[:id]).collect {|id|
62
- (id =~ /_(#{Runo::REX::ID_SHORT})$/) ? $1 : (id if Runo::REX::ID)
63
- }.compact
64
- if (ids.size == 1) && (ids.first =~ Runo::REX::ID)
65
- '%s/%d/' % [$1, $2.to_i]
66
- elsif ids.size > 0
67
- "id=#{ids.join ','}/"
68
- end
69
- elsif cid == :d
70
- conds[:id] ? '' : "#{conds[:d]}/"
71
- else
72
- "#{cid}=#{Array(conds[cid]).join ','}/"
73
- end
74
- }.join.sub(%r{/p=1/$}, '/')
75
- end
76
-
77
- def _dirname(path) # returns '/foo/bar/' for '/foo/bar/'
78
- path[%r{^.*/}] || ''
79
- end
80
-
81
- def _basename(path) # returns nil for '/foo/bar/'
82
- path[%r{[^/]+$}]
83
- end
84
-
85
- end
86
-
@@ -1,215 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- class Runo::Storage
7
-
8
- def self.instance(sd)
9
- if folder = sd[:folder]
10
- if folder != sd[:parent]
11
- Temp.new sd
12
- else
13
- klass = Runo['storage']['default'].capitalize
14
- self.const_get(klass).new sd
15
- end
16
- else
17
- Temp.new sd
18
- end
19
- end
20
-
21
- def self.available?
22
- false
23
- end
24
-
25
- attr_reader :sd
26
-
27
- def initialize(sd)
28
- @sd = sd
29
- end
30
-
31
- def persistent?
32
- true
33
- end
34
-
35
- def order
36
- @sd[:order]
37
- end
38
-
39
- def select(conds = {})
40
- _cast conds
41
- item_ids = _select(conds)
42
- item_ids = _sort(item_ids, conds)
43
- item_ids = _page(item_ids, conds)
44
- ((conds[:order] || order) =~ /^-/) ? item_ids.reverse : item_ids
45
- end
46
-
47
- def build(v)
48
- self
49
- end
50
-
51
- def clear
52
- self
53
- end
54
-
55
- def store(id, v)
56
- id
57
- end
58
-
59
- def delete(id)
60
- id
61
- end
62
-
63
- def navi(conds)
64
- conds[:p] = '1' unless conds[:p] || conds[:id] || (@sd[:p_size].to_i < 1)
65
- navi = {}
66
- (([:id, :p, :d] & conds.keys) | conds.keys).each {|cid|
67
- next unless conds[cid] && respond_to?("_sibs_#{cid}", true)
68
- sibs = __send__("_sibs_#{cid}", conds)
69
-
70
- c = (c.is_a?(::Array) && c.size < 2) ? conds[cid].first : conds[cid]
71
- if i = sibs.index(c)
72
- if !navi[:prev] && i > 0
73
- navi[:prev] = conds.merge(cid => sibs[i - 1])
74
- if ![:id, :p].include? cid
75
- navi[:prev][:id] = _select_without(:id, navi[:prev]).last if conds[:id]
76
- navi[:prev][:p] = _p_count(navi[:prev]).to_s if conds[:p]
77
- end
78
- end
79
- if !navi[:next] && i < (sibs.size - 1)
80
- navi[:next] = conds.merge(cid => sibs[i + 1])
81
- if ![:id, :p].include? cid
82
- navi[:next][:id] = _select_without(:id, navi[:next]).first if conds[:id]
83
- navi[:next][:p] = '1' if conds[:p]
84
- end
85
- end
86
- end
87
- navi[:sibs] ||= {cid => sibs} if navi[:prev] || navi[:next]
88
-
89
- break if navi[:prev] && navi[:next]
90
- }
91
-
92
- navi
93
- end
94
-
95
- def last(cid, conds)
96
- __send__("_sibs_#{cid}", conds).last
97
- end
98
-
99
- private
100
-
101
- def _cast(conds)
102
- ([:d, :id, :p] & conds.keys).each {|cid|
103
- case cid
104
- when :d
105
- conds[:d] = conds[:d].first if conds[:d].is_a? ::Array
106
- conds[:d] = conds[:d].to_s
107
- conds[:d] = last(:d, conds) if conds[:d] =~ /9999(99)?(99)?/
108
- conds[:d] = nil unless conds[:d] =~ Runo::REX::COND_D
109
- when :id
110
- conds[:id] = Array(conds[:id]).collect {|id|
111
- case id
112
- when '99999999_9999', 'last'
113
- last(:id, conds)
114
- when /\A#{Runo::REX::ID_SHORT}\z/
115
- "00000000_#{id}"
116
- when Runo::REX::ID, Runo::REX::ID_NEW
117
- id
118
- end
119
- }.uniq.compact
120
- when :p
121
- conds[:p] = conds[:p].first if conds[:p].is_a? ::Array
122
- conds[:p] = conds[:p].to_s
123
- conds[:p] = last(:p, conds) if conds[:p] == 'last'
124
- conds[:p] = nil unless conds[:p] =~ /^\d+$/
125
- end
126
- }
127
- conds
128
- end
129
-
130
- def _select(conds)
131
- if conds[:id]
132
- _select_by_id(conds) | (@sd.instance_variable_get(:@item_object).keys & Array(conds[:id]))
133
- elsif cid = (conds.keys - [:order, :p]).first
134
- m = "_select_by_#{cid}"
135
- respond_to?(m, true) ? __send__(m, conds) : []
136
- else
137
- _select_all(conds) | @sd.instance_variable_get(:@item_object).keys
138
- end
139
- end
140
-
141
- def _sort(item_ids, conds)
142
- item_ids.sort
143
- end
144
-
145
- def _page(item_ids, conds)
146
- size = @sd[:p_size].to_i
147
- return item_ids if size < 1
148
-
149
- page = conds[:p].to_i
150
- page = 1 if page < 1
151
- Array item_ids[(page - 1) * size, size]
152
- end
153
-
154
- def _sibs_id(conds)
155
- _select_without(:id, conds)
156
- end
157
-
158
- def _sibs_p(conds)
159
- p_count = _p_count(conds)
160
- p_count ? (1..p_count).collect {|i| i.to_s } : []
161
- end
162
-
163
- def _sibs_d(conds)
164
- rex_d = /^\d{#{conds[:d].length}}/
165
- _select_without(:id, :p, :d, conds).collect {|id| id[rex_d] }.uniq.compact
166
- end
167
-
168
- def _select_without(*cids)
169
- conds = cids.pop.dup
170
- cids.each {|cid| conds.delete cid }
171
- _sort(_select(conds), conds)
172
- end
173
-
174
- def _p_count(conds)
175
- (_select_without(:id, :p, conds).size / @sd[:p_size].to_f).ceil unless @sd[:p_size].to_f == 0
176
- end
177
-
178
- def cast_ids(ids)
179
- Array(ids).collect {|i|
180
- id = (i =~ /^[a-z]/) ? "00000000_#{i}" : i
181
- id if id =~ Runo::REX::ID
182
- }.compact
183
- end
184
-
185
- def new_id(v = {})
186
- return "00000000_#{v['_id']}" if v.is_a?(::Hash) && v['_id'] =~ /\A#{Runo::REX::ID_SHORT}\z/
187
-
188
- if v.is_a?(::Hash) && v['_timestamp'] && v['_timestamp']['published'].is_a?(::Time)
189
- d = v['_timestamp']['published'].strftime '%Y%m%d'
190
- else
191
- d = Time.now.strftime '%Y%m%d'
192
- end
193
- if max_in_d = _select(:d => d).sort.last
194
- max_in_d.succ
195
- else
196
- d + '_0001'
197
- end
198
- end
199
-
200
- def new_id?(id, v)
201
- if id == :new_id
202
- true
203
- elsif !v.is_a?(::Hash)
204
- false
205
- elsif id =~ /_#{Runo::REX::ID_SHORT}\z/
206
- v['_id'] =~ /\A#{Runo::REX::ID_SHORT}\z/ &&
207
- id != new_id(v)
208
- else
209
- v['_timestamp'] &&
210
- v['_timestamp']['published'].is_a?(::Time) &&
211
- id !~ /\A#{v['_timestamp']['published'].strftime('%Y%m%d')}/
212
- end
213
- end
214
-
215
- end
@@ -1,201 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- require 'rubygems'
7
- require 'yaml'
8
- require 'ya2yaml'
9
- require 'fileutils'
10
-
11
- class Runo::Storage::File < Runo::Storage
12
-
13
- def self.traverse(dir = '/', root = Runo['storage']['File']['data_dir'], &block)
14
- ::Dir.glob(::File.join(root, dir, '*')).sort.collect {|file|
15
- ftype = ::File.ftype file
16
- base_name = ::File.basename file
17
- id, ext = base_name.split('.', 2)
18
- id = "main-#{id}" if id =~ Runo::REX::ID
19
- full_name = ::File.join(dir, id).gsub(::File::SEPARATOR, '-')
20
-
21
- if ftype == 'file' && id.sub(/^([^\d\-]+-)+/, '') =~ Runo::REX::ID
22
- val = nil
23
- ::File.open(file, 'r') {|f|
24
- f.flock ::File::LOCK_SH
25
- f.binmode
26
- val = f.read
27
- f.flock ::File::LOCK_UN
28
- }
29
- block.call(
30
- :dir => dir,
31
- :base_name => base_name,
32
- :full_name => full_name,
33
- :ext => ext,
34
- :val => (ext == 'yaml' ? YAML.load(val) : val)
35
- )
36
- elsif ftype == 'directory' && base_name !~ /\A#{Runo::REX::DIR_STATIC}\z/
37
- self.traverse(::File.join(dir, base_name), root, &block)
38
- end
39
- }.compact.flatten
40
- end
41
-
42
- def self.load_skel
43
- self.traverse('/', Runo['skin_dir']) {|entry|
44
- dir = ::File.join(Runo['storage']['File']['data_dir'], entry[:dir])
45
- unless ::File.exists? ::File.join(dir, entry[:base_name])
46
- ::FileUtils.mkpath(dir) unless ::File.directory? dir
47
- ::FileUtils.cp(
48
- ::File.join(Runo['skin_dir'], entry[:dir], entry[:base_name]),
49
- ::File.join(dir, entry[:base_name]),
50
- {:preserve => true}
51
- )
52
- end
53
- }
54
- end
55
-
56
- def self.available?
57
- Runo['storage']['File'] && Runo['storage']['File']['data_dir']
58
- end
59
-
60
- def initialize(sd)
61
- super
62
- unless @@loaded ||= false
63
- entries = ::Dir.glob ::File.join(Runo['storage']['File']['data_dir'], '*')
64
- self.class.load_skel if entries.empty?
65
- @@loaded = true
66
- end
67
- @dir = ::File.join(Runo['storage']['File']['data_dir'], @sd[:folder][:dir])
68
- ::FileUtils.mkpath(@dir) unless ::File.directory? @dir
69
- end
70
-
71
- def val(id = nil)
72
- if id
73
- load id
74
- else
75
- # this could be HUGE.
76
- _select_all({}).inject({}) {|v, id|
77
- v[id] = load id
78
- v
79
- }
80
- end
81
- end
82
-
83
- def build(v)
84
- clear
85
- v.each {|id, v| store(id, v) }
86
- self
87
- end
88
-
89
- def clear
90
- glob.each {|file| ::File.unlink ::File.join(@dir, file) }
91
- self
92
- end
93
-
94
- def store(id, v, ext = nil)
95
- save(id, v, ext)
96
- end
97
-
98
- def delete(id)
99
- remove_file(id) && id
100
- end
101
-
102
- def move(old_id, new_id)
103
- rename_file(old_id, new_id) && new_id
104
- end
105
-
106
- private
107
-
108
- def _select_by_id(conds)
109
- glob(Array(conds[:id])).collect {|f| f[/\d.*/][Runo::REX::ID] }.compact
110
- end
111
-
112
- def _select_by_d(conds)
113
- glob(conds[:d].to_s).collect {|f| f[/\.yaml$/] && f[/\d.*/][Runo::REX::ID] }.compact
114
- end
115
-
116
- def _select_all(conds)
117
- glob.collect {|f| f[/\.yaml$/] && f[/\d.*/][Runo::REX::ID] }.compact
118
- end
119
-
120
- def glob(id = :all)
121
- glob_pattern = "#{file_prefix}#{pattern_for id}.[a-z]*"
122
- ::Dir.chdir(@dir) { ::Dir.glob glob_pattern }
123
- end
124
-
125
- def file_prefix
126
- (@sd[:name] == 'main') ? '' : @sd[:name].sub(/^main-/, '') + '-'
127
- end
128
-
129
- def pattern_for(id)
130
- if id.is_a? Array
131
- "{#{id.join ','}}"
132
- elsif id == :all
133
- '[0-9]*_*'
134
- elsif id =~ /\A\d{4,8}\z/
135
- "#{id}*"
136
- end
137
- end
138
-
139
- def load(id)
140
- v = nil
141
- file = glob(Array(id)).sort.first
142
- ::File.open(::File.join(@dir, file), 'r') {|f|
143
- f.flock ::File::LOCK_SH
144
- f.binmode
145
- v = f.read
146
- f.flock ::File::LOCK_UN
147
- } if file
148
- (file[/\.yaml$/] ? YAML.load(v) : v) if v
149
- end
150
-
151
- def save(id, v, ext)
152
- if new_id?(id, v)
153
- old_id = id
154
- id = new_id v
155
- end
156
-
157
- if ext
158
- val = v
159
- ext = 'y' if ext == 'yaml'
160
- remove_file id
161
- else
162
- val = v.ya2yaml(:syck_compatible => true)
163
- ext = 'yaml'
164
- end
165
-
166
- file = "#{file_prefix}#{id}.#{ext}"
167
- if old_id && f = ::File.open(::File.join(@dir, file), 'a')
168
- f.seek(0, IO::SEEK_END)
169
- return if f.pos != 0 # duplicate id
170
- move(old_id, id) unless old_id == :new_id
171
- end
172
- ::File.open(::File.join(@dir, file), 'a') {|f|
173
- f.flock ::File::LOCK_EX
174
- f.binmode
175
- f.seek 0
176
- f.truncate 0
177
- f << val
178
- f.flock ::File::LOCK_UN
179
- f.chmod 0664
180
- } && id
181
- end
182
-
183
- def remove_file(id)
184
- glob_pattern = "#{file_prefix}#{pattern_for Array(id)}[.-]*"
185
- files = ::Dir.chdir(@dir) { ::Dir.glob glob_pattern } # may include child files
186
- files.each {|file|
187
- ::File.unlink ::File.join(@dir, file)
188
- }
189
- end
190
-
191
- def rename_file(old_id, new_id)
192
- glob_pattern = "#{file_prefix}#{pattern_for Array(old_id)}*"
193
- files = ::Dir.chdir(@dir) { ::Dir.glob glob_pattern } # may include child files
194
- rex = /^\A#{file_prefix}#{old_id}/
195
- files.each {|file|
196
- to_file = file.sub(rex, "#{file_prefix}#{new_id}")
197
- ::File.rename(::File.join(@dir, file), ::File.join(@dir, to_file))
198
- }
199
- end
200
-
201
- end