ro 1.1.1 → 1.2.0

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.
@@ -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