ro 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,14 +19,21 @@ module Tilt
19
19
  Redcarpet::Markdown.new(
20
20
  syntax_highlighting_renderer,
21
21
 
22
- :no_intra_emphasis => true,
23
- :tables => true,
24
- :fenced_code_blocks => true,
25
- :autolink => true,
26
- :strikethrough => true,
27
- :lax_html_blocks => true,
28
- :space_after_headers => true,
29
- :superscript => true
22
+ :no_intra_emphasis => true,
23
+ :tables => true,
24
+ :fenced_code_blocks => true,
25
+ :autolink => true,
26
+ :disable_indented_code_blocks => true,
27
+ :strikethrough => true,
28
+ :lax_spacing => true,
29
+ :space_after_headers => false,
30
+ :superscript => true,
31
+ :underline => true,
32
+ :highlight => true,
33
+ :quote => true,
34
+
35
+ :with_toc_data => true,
36
+ :hard_wrap => true,
30
37
  )
31
38
 
32
39
  @output = nil
data/lib/ro/lock.rb ADDED
@@ -0,0 +1,53 @@
1
+ module Ro
2
+ class Lock
3
+ def initialize(path)
4
+ @path = path.to_s
5
+ @fd = false
6
+ end
7
+
8
+ def lock(&block)
9
+ open!
10
+
11
+ if block
12
+ begin
13
+ lock!
14
+ block.call
15
+ ensure
16
+ unlock!
17
+ end
18
+ else
19
+ self
20
+ end
21
+ end
22
+
23
+ def open!
24
+ @fd ||= (
25
+ fd =
26
+ begin
27
+ open(@path, 'ab+')
28
+ rescue
29
+ unless test(?e, @path)
30
+ FileUtils.mkdir_p(@path)
31
+ FileUtils.touch(@path)
32
+ end
33
+
34
+ open(@path, 'ab+')
35
+ end
36
+
37
+ fd.close_on_exec = true
38
+
39
+ fd
40
+ )
41
+ end
42
+
43
+ def lock!
44
+ open!
45
+ @fd.flock File::LOCK_EX
46
+ end
47
+
48
+ def unlock!
49
+ open!
50
+ @fd.flock File::LOCK_UN
51
+ end
52
+ end
53
+ end
data/lib/ro/model.rb ADDED
@@ -0,0 +1,150 @@
1
+ begin
2
+ require 'active_model'
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string/inflections.rb'
5
+ rescue LoadError => e
6
+ abort "you need to add the 'active_model' and 'active_support' gems to use Ro::Model"
7
+ end
8
+
9
+ module Ro
10
+ class Model
11
+ #
12
+ extend ActiveModel::Naming
13
+ extend ActiveModel::Translation
14
+ include ActiveModel::Validations
15
+ include ActiveModel::Conversion
16
+
17
+ #
18
+ Fattr(:collection){ default_collection_name }
19
+ Fattr(:default_collection_name){ self.name.to_s.split(/::/).last.underscore.pluralize }
20
+ Fattr(:root){ Ro.root }
21
+ Fattr(:prefix){ File.join(root, collection) }
22
+
23
+ def Model.nodes(*args, &block)
24
+ root.nodes.send(collection)
25
+ end
26
+
27
+ def Model.all(*args, &block)
28
+ models_for(nodes)
29
+ end
30
+
31
+ def Model.select(*args, &block)
32
+ all.select(*args, &block)
33
+ end
34
+
35
+ def Model.detect(*args, &block)
36
+ all.detect(*args, &block)
37
+ end
38
+
39
+ def Model.count(*args, &block)
40
+ if args.empty? and block.nil?
41
+ all.size
42
+ else
43
+ where(*args, &block).size
44
+ end
45
+ end
46
+
47
+ def Model.where(*args, &block)
48
+ all.select do |model|
49
+ !!model.instance_eval(&block)
50
+ end
51
+ end
52
+
53
+ def Model.first
54
+ all.first
55
+ end
56
+
57
+ def Model.last
58
+ all.last
59
+ end
60
+
61
+ def Model.find(*args, &block)
62
+ models_for(nodes.find(*args, &block))
63
+ end
64
+
65
+ def Model.paginate(*args, &block)
66
+ models_for(nodes.paginate(*args, &block))
67
+ end
68
+
69
+ def Model.models_for(result)
70
+ case result
71
+ when Array
72
+ Array(result).flatten.compact.map{|element| new(element)}
73
+ else
74
+ new(result)
75
+ end
76
+ end
77
+
78
+ #
79
+ attr_accessor(:node)
80
+
81
+ def initialize(*args, &block)
82
+ attributes = Map.options_for!(args)
83
+
84
+ node = args.detect{|arg| arg.is_a?(Node)}
85
+ model = args.detect{|arg| arg.is_a?(Model)}
86
+
87
+ if node.nil? and not model.nil?
88
+ node = model.node
89
+ end
90
+
91
+ if node
92
+ @node = node
93
+ else
94
+ path = File.join(prefix, ':new')
95
+ node = Node.new(path)
96
+ @node = node
97
+ end
98
+ end
99
+
100
+ def attributes
101
+ @node.attributes
102
+ end
103
+
104
+ #
105
+ def prefix
106
+ self.class.prefix
107
+ end
108
+
109
+ def directory
110
+ File.join(prefix, id)
111
+ end
112
+
113
+ #
114
+ def method_missing(method, *args, &block)
115
+ node.send(method, *args, &block)
116
+ end
117
+ end
118
+ end
119
+
120
+
121
+
122
+
123
+ if __FILE__ == $0
124
+
125
+ ENV['RO_ROOT'] = '../sample_ro_data'
126
+
127
+ class Person < Ro::Model
128
+
129
+ #field(:first_name, :type => :string)
130
+
131
+ end
132
+
133
+ p Person.collection
134
+ p Person.all
135
+ p Person.find(:ara).attributes
136
+ ara = Person.find(:ara)
137
+
138
+ p ara.url_for(:ara_glacier)
139
+
140
+ p Person.paginate(:per => 2, :page => 1)
141
+ p Person.name
142
+
143
+ p Person.prefix
144
+ p ara.id
145
+ p ara.first_name
146
+
147
+ require 'pry'
148
+ binding.pry
149
+
150
+ end
data/lib/ro/node.rb CHANGED
@@ -5,6 +5,7 @@ module Ro
5
5
  fattr :name
6
6
  fattr :type
7
7
  fattr :loaded
8
+ fattr :fields
8
9
 
9
10
  def initialize(path)
10
11
  @path = Ro.realpath(path.to_s)
@@ -14,12 +15,17 @@ module Ro
14
15
  @loaded = false
15
16
  @loading = false
16
17
  @attributes = Map.new
18
+ @fields = Map.new
17
19
  end
18
20
 
19
21
  def id
20
22
  @name
21
23
  end
22
24
 
25
+ def slug
26
+ attributes[:slug] || id
27
+ end
28
+
23
29
  def identifier
24
30
  "#{ type }/#{ name }"
25
31
  end
@@ -52,6 +58,24 @@ module Ro
52
58
  File.join(relative_path, 'assets')
53
59
  end
54
60
 
61
+ def asset_dir
62
+ File.join(path, 'assets')
63
+ end
64
+
65
+ def asset_paths
66
+ Dir.glob("#{ asset_dir }/**/**").select{|entry| test(?f, entry)}
67
+ end
68
+
69
+ def assets
70
+ asset_paths.map do |asset|
71
+ asset.sub(asset_dir + "/", "")
72
+ end
73
+ end
74
+
75
+ def asset_urls
76
+ asset_names.map{|asset_name| url_for(asset_name)}
77
+ end
78
+
55
79
  def url_for(*args, &block)
56
80
  options = Map.options_for!(args)
57
81
 
@@ -61,11 +85,13 @@ module Ro
61
85
 
62
86
  path = File.join(@path.to_s, 'assets', path_info)
63
87
 
88
+ glob = path_info.gsub(/[_-]/, '[_-]')
89
+
64
90
  globs =
65
91
  [
66
- File.join(@path.to_s, 'assets', "#{ path_info }"),
67
- File.join(@path.to_s, 'assets', "#{ path_info }*"),
68
- File.join(@path.to_s, 'assets', "**/#{ path_info }")
92
+ File.join(@path.to_s, 'assets', "#{ glob }"),
93
+ File.join(@path.to_s, 'assets', "#{ glob }*"),
94
+ File.join(@path.to_s, 'assets', "**/#{ glob }")
69
95
  ]
70
96
 
71
97
  candidates = globs.map{|glob| Dir.glob(glob)}.flatten.compact.uniq
@@ -79,14 +105,15 @@ module Ro
79
105
  path_info = path.gsub(/^#{ Regexp.escape(Ro.root) }/, '')
80
106
 
81
107
  if cache_buster
82
- timestamp = File.stat(path).mtime.to_i
108
+ #options['_'] = Ro.md5(IO.binread(path))
109
+ timestamp = File.stat(path).mtime.utc.to_i
83
110
  options['_'] = timestamp
84
111
  end
85
112
  else
86
113
  raise ArgumentError.new("too many assets (#{ candidates.inspect }) matching #{ globs.inspect }")
87
114
  end
88
115
 
89
- url = File.join(Ro.mount, path_info)
116
+ url = File.join(Ro.route, path_info)
90
117
 
91
118
  if options.empty?
92
119
  url
@@ -96,13 +123,21 @@ module Ro
96
123
  end
97
124
  end
98
125
 
126
+ def url_for?(*args, &block)
127
+ begin
128
+ url_for(*args, &block)
129
+ rescue
130
+ nil
131
+ end
132
+ end
133
+
99
134
  def source_for(*args)
100
135
  key = Ro.relative_path_for(:assets, :source, args).split('/')
101
136
  get(key)
102
137
  end
103
138
 
104
- def mount(*args)
105
- path_info = Ro.absolute_path_for(Ro.mount, relative_path)
139
+ def route(*args)
140
+ path_info = Ro.absolute_path_for(Ro.route, relative_path)
106
141
  [Ro.asset_host, path_info].compact.join('/')
107
142
  end
108
143
 
@@ -180,6 +215,15 @@ module Ro
180
215
  }
181
216
  end
182
217
 
218
+ def reload(&block)
219
+ @loaded = false
220
+ _load(&block)
221
+ end
222
+
223
+ def loaded
224
+ attributes
225
+ end
226
+
183
227
  def _load(&block)
184
228
  unless @loaded
185
229
  if @loading
@@ -213,7 +257,7 @@ module Ro
213
257
  _load_attributes_yml
214
258
  _load_attribute_files
215
259
  _load_sources
216
- _load_urls
260
+ _load_assets
217
261
 
218
262
  Ro.cache.write(cache_key, @attributes)
219
263
 
@@ -238,19 +282,24 @@ module Ro
238
282
  end
239
283
 
240
284
  def _load_attribute_files
241
- glob = File.join(@path, '*')
285
+ glob = File.join(@path, '**/**')
242
286
  node = self
243
287
 
244
288
  Dir.glob(glob) do |path|
245
289
  next if test(?d, path)
246
290
 
247
291
  basename = File.basename(path)
248
- key, ext = basename.split('.', 2)
249
-
250
292
  next if basename == 'attributes.yml'
251
293
 
252
- value = Ro.render(path, node)
253
- @attributes.set(key => value)
294
+ relative_path = Ro.relative_path(path, :to => @path)
295
+ next if relative_path =~ /^assets\//
296
+
297
+ key = relative_path.split('.', 2).first.split('/')
298
+
299
+ html = Ro.render(path, node)
300
+ html = Ro.expand_asset_urls(html, node)
301
+
302
+ @attributes.set(key => html)
254
303
  end
255
304
  end
256
305
 
@@ -271,7 +320,7 @@ module Ro
271
320
  end
272
321
  end
273
322
 
274
- def _load_urls
323
+ def _load_assets
275
324
  glob = File.join(@path, 'assets/**/**')
276
325
  node = self
277
326
 
@@ -311,11 +360,11 @@ module Ro
311
360
  entries.push([relative_path, timestamp.iso8601(2)])
312
361
  end
313
362
 
314
- signature = entries.map{|pair| pair.join('@')}.join(', ')
363
+ fingerprint = entries.map{|pair| pair.join('@')}.join(', ')
315
364
 
316
- md5 = Ro.md5(signature)
365
+ md5 = Ro.md5(fingerprint)
317
366
 
318
- "#{ @path }-#{ md5 }"
367
+ [@path, md5]
319
368
  end
320
369
 
321
370
  def _load_from_cache
data/lib/ro/node/list.rb CHANGED
@@ -18,6 +18,10 @@ module Ro
18
18
  block.call(self) if block
19
19
  end
20
20
 
21
+ def nodes
22
+ self
23
+ end
24
+
21
25
  def load(path)
22
26
  add( node = Node.new(path) )
23
27
  end
@@ -46,15 +50,22 @@ module Ro
46
50
  related
47
51
  end
48
52
 
49
- def [](key)
50
- if @type.nil?
51
- type = key.to_s
52
- list = select{|node| type == node.type}
53
- list.type = type
54
- list
55
- else
56
- name = key.to_s
57
- detect{|node| name == node.name}
53
+ def [](*args, &block)
54
+ key = args.first
55
+
56
+ case key
57
+ when String, Symbol
58
+ if @type.nil?
59
+ type = key.to_s
60
+ list = select{|node| type == node.type}
61
+ list.type = type
62
+ list
63
+ else
64
+ name = Slug.for(key.to_s)
65
+ detect{|node| name == node.name}
66
+ end
67
+ else
68
+ super(*args, &block)
58
69
  end
59
70
  end
60
71
 
@@ -103,6 +114,72 @@ module Ro
103
114
  [root, type].compact.join('/')
104
115
  end
105
116
 
117
+ def paginate(*args)
118
+ options = Map.options_for!(args)
119
+
120
+ ensure_pagination_state!
121
+
122
+ page = Integer(args.shift || options[:page] || @page)
123
+ per = Integer(args.shift || options[:per] || options[:size] || @per)
124
+
125
+ @page = [page.abs, 1].max
126
+ @per = [per.abs, 1].max
127
+
128
+ offset = (@page - 1) * @per
129
+ length = @per
130
+
131
+ replace(self.slice(offset, length))
132
+
133
+ self
134
+ end
135
+
136
+ def page(*args)
137
+ ensure_pagination_state!
138
+
139
+ if args.empty?
140
+ return @page
141
+ else
142
+ options = Map.options_for!(args)
143
+ page = args.shift || options[:page]
144
+ options[:page] = page
145
+ paginate(options)
146
+ end
147
+ end
148
+
149
+ alias_method(:current_page, :page)
150
+
151
+ def per(*args)
152
+ ensure_pagination_state!
153
+
154
+ if args.empty?
155
+ return @per
156
+ else
157
+ options = Map.options_for!(args)
158
+ per = args.shift || options[:per]
159
+ options[:per] = per
160
+ paginate(options)
161
+ end
162
+ end
163
+
164
+ def num_pages
165
+ (size.to_f / per).ceil
166
+ end
167
+
168
+ def total_pages
169
+ num_pages
170
+ end
171
+
172
+ def ensure_pagination_state!
173
+ unless defined?(@page)
174
+ @page = 1
175
+ end
176
+ unless defined?(@per)
177
+ @per = size
178
+ end
179
+ [@page, @per]
180
+ end
181
+
182
+
106
183
  def method_missing(method, *args, &block)
107
184
  Ro.log "Ro::List(#{ identifier })#method_missing(#{ method.inspect }, #{ args.inspect })"
108
185
 
@@ -112,8 +189,7 @@ module Ro
112
189
  super unless list
113
190
  list.empty? ? super : list
114
191
  else
115
- name = Ro.slug_for(method)
116
- node = self[name]
192
+ node = self[Slug.for(method, :join => '-')] || self[Slug.for(method, :join => '_')]
117
193
  node.nil? ? super : node
118
194
  end
119
195
  end