ro 1.4.6 → 4.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.
Files changed (66) hide show
  1. checksums.yaml +6 -14
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +43 -0
  4. data/LICENSE +1 -0
  5. data/README.md +120 -112
  6. data/README.md.erb +159 -0
  7. data/Rakefile +129 -78
  8. data/bin/ro +241 -68
  9. data/lib/ro/_lib.rb +95 -0
  10. data/lib/ro/asset.rb +45 -0
  11. data/lib/ro/collection/list.rb +23 -0
  12. data/lib/ro/collection.rb +168 -0
  13. data/lib/ro/config.rb +68 -0
  14. data/lib/ro/error.rb +8 -0
  15. data/lib/ro/klass.rb +25 -0
  16. data/lib/ro/methods.rb +238 -0
  17. data/lib/ro/model.rb +83 -114
  18. data/lib/ro/node.rb +177 -360
  19. data/lib/ro/pagination.rb +7 -4
  20. data/lib/ro/path.rb +225 -0
  21. data/lib/ro/root.rb +52 -31
  22. data/lib/ro/script/builder.rb +221 -0
  23. data/lib/ro/script/console.rb +47 -0
  24. data/lib/ro/script/server.rb +76 -0
  25. data/lib/ro/script.rb +189 -0
  26. data/lib/ro/slug.rb +19 -18
  27. data/lib/ro/template/rouge_formatter.rb +42 -0
  28. data/lib/ro/template.rb +104 -50
  29. data/lib/ro.rb +85 -317
  30. data/public/api/ro/index-1.json +147 -0
  31. data/public/api/ro/index.json +137 -0
  32. data/public/api/ro/posts/first_post/index.json +52 -0
  33. data/public/api/ro/posts/index-1.json +145 -0
  34. data/public/api/ro/posts/index.json +135 -0
  35. data/public/api/ro/posts/second_post/index.json +51 -0
  36. data/public/api/ro/posts/third_post/index.json +51 -0
  37. data/public/ro/posts/first_post/assets/foo/bar/baz.jpg +0 -0
  38. data/public/ro/posts/first_post/assets/foo.jpg +0 -0
  39. data/public/ro/posts/first_post/assets/src/foo/bar.rb +3 -0
  40. data/public/ro/posts/first_post/attributes.yml +2 -0
  41. data/public/ro/posts/first_post/blurb.erb.md +7 -0
  42. data/public/ro/posts/first_post/body.md +16 -0
  43. data/public/ro/posts/first_post/testing.txt +3 -0
  44. data/public/ro/posts/second_post/assets/foo/bar/baz.jpg +0 -0
  45. data/public/ro/posts/second_post/assets/foo.jpg +0 -0
  46. data/public/ro/posts/second_post/assets/src/foo/bar.rb +3 -0
  47. data/public/ro/posts/second_post/attributes.yml +2 -0
  48. data/public/ro/posts/second_post/blurb.erb.md +5 -0
  49. data/public/ro/posts/second_post/body.md +16 -0
  50. data/public/ro/posts/third_post/assets/foo/bar/baz.jpg +0 -0
  51. data/public/ro/posts/third_post/assets/foo.jpg +0 -0
  52. data/public/ro/posts/third_post/assets/src/foo/bar.rb +3 -0
  53. data/public/ro/posts/third_post/attributes.yml +2 -0
  54. data/public/ro/posts/third_post/blurb.erb.md +5 -0
  55. data/public/ro/posts/third_post/body.md +16 -0
  56. data/ro.gemspec +89 -29
  57. metadata +106 -90
  58. data/TODO.md +0 -50
  59. data/lib/ro/blankslate.rb +0 -7
  60. data/lib/ro/cache.rb +0 -26
  61. data/lib/ro/git.rb +0 -374
  62. data/lib/ro/initializers/env.rb +0 -5
  63. data/lib/ro/initializers/tilt.rb +0 -104
  64. data/lib/ro/lock.rb +0 -53
  65. data/lib/ro/node/list.rb +0 -142
  66. data/notes/ara.txt +0 -215
data/lib/ro/config.rb ADDED
@@ -0,0 +1,68 @@
1
+ module Ro
2
+ class Config < ::Map
3
+ def Config.defaults
4
+ {
5
+ :root =>
6
+ (Ro.env.root || Ro.defaults.root),
7
+
8
+ :build =>
9
+ (Ro.env.build || Ro.defaults.build),
10
+
11
+ :url =>
12
+ (Ro.env.url || Ro.defaults.url),
13
+
14
+ :page_size =>
15
+ (Ro.env.page_size || Ro.defaults.page_size),
16
+
17
+ :log =>
18
+ (Ro.env.log || Ro.defaults.log),
19
+
20
+ :debug =>
21
+ (Ro.env.debug || Ro.defaults.debug),
22
+
23
+ :port =>
24
+ (Ro.env.port || Ro.defaults.port),
25
+
26
+ :md_theme =>
27
+ (Ro.env.md_theme || Ro.defaults.md_theme),
28
+ }
29
+ end
30
+
31
+ def initialize(*args, **kws)
32
+ configure!(Config.defaults)
33
+
34
+ args.each do |arg|
35
+ configure!(arg) if arg.is_a?(Hash)
36
+ end
37
+
38
+ configure!(kws)
39
+ end
40
+
41
+ def configure!(hash)
42
+ hash.each do |key, value|
43
+ send("#{ key }=", value)
44
+ end
45
+ end
46
+
47
+ {
48
+ :root => :root,
49
+ :build => :path,
50
+ :url => :url,
51
+ :page_size => :int,
52
+ :log => :bool,
53
+ :debug => :bool,
54
+ :port => :int,
55
+ :md_theme => :string,
56
+ }.each do |attribute, cast|
57
+ class_eval <<-____, __FILE__, __LINE__ + 1
58
+ def #{ attribute }
59
+ get :#{ attribute }
60
+ end
61
+
62
+ def #{ attribute }=(value)
63
+ set :#{ attribute }, Ro.cast(:#{ cast }, value)
64
+ end
65
+ ____
66
+ end
67
+ end
68
+ end
data/lib/ro/error.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Ro
2
+ class Error < ::StandardError
3
+ def initialize(message, context = nil)
4
+ super(message)
5
+ @context = context
6
+ end
7
+ end
8
+ end
data/lib/ro/klass.rb ADDED
@@ -0,0 +1,25 @@
1
+ module Ro
2
+ module Klass
3
+ module ClassMethods
4
+ def klass(arg, *args, **kws, &block)
5
+ return arg if arg.is_a?(self.class) && args.empty? && kws.empty? && block.nil?
6
+
7
+ new(arg, *args, **kws, &block)
8
+ end
9
+
10
+ alias for klass
11
+ end
12
+
13
+ module InstanceMethods
14
+ def klass
15
+ self.class
16
+ end
17
+ end
18
+
19
+ def Klass.included(other)
20
+ other.send(:extend, ClassMethods)
21
+ other.send(:include, InstanceMethods)
22
+ super
23
+ end
24
+ end
25
+ end
data/lib/ro/methods.rb ADDED
@@ -0,0 +1,238 @@
1
+ module Ro
2
+ module Methods
3
+ # cast methods
4
+ # |
5
+ # v
6
+ def cast(which, arg, *args)
7
+ which = which.to_s
8
+ values = [arg, *args].join(',').scan(/[^,\s]+/)
9
+
10
+ list_of = which.match(/^list_of_(.+)$/)
11
+ which = list_of[1] if list_of
12
+
13
+ cast = casts.fetch(which.to_s.to_sym)
14
+
15
+ if list_of
16
+ values.map { |value| cast[value] }
17
+ else
18
+ raise ArgumentError, "too many values in #{values.inspect}" if values.size > 1
19
+
20
+ value = values.first
21
+ cast[value]
22
+ end
23
+ end
24
+
25
+ def casts
26
+ {
27
+ :string => proc { |value| String(value) },
28
+ :int => proc { |value| Integer(value.to_s) },
29
+ :string_or_nil => proc { |value| String(value).empty? ? nil : String(value) },
30
+ :url => proc { |value| Ro.normalize_url(value) },
31
+ :array => proc { |value| String(value).scan(/[^,:]+/) },
32
+ :bool => proc { |value| String(value) !~ /^\s*(f|false|off|no|0){0,1}\s*$/ },
33
+ :path => proc { |value| Path.for(value) },
34
+ :path_or_nil => proc { |value| String(value).empty? ? nil : Path.for(value) },
35
+ :root => proc { |value| Root.for(value) },
36
+ :time => proc { |value| Time.parse(value.to_s) },
37
+ :date => proc { |value| Date.parse(value.to_s) },
38
+ }
39
+ end
40
+
41
+ def mapify(pod)
42
+ Map.for(:pod => pod)[:pod]
43
+ end
44
+
45
+ def pod(object)
46
+ JSON.parse(object.to_json)
47
+ end
48
+
49
+ # url methods
50
+ # |
51
+ # v
52
+ def url_for(path, *args)
53
+ options = Map.extract_options!(args)
54
+ base = options[:base] || options[:url] || Ro.config.url
55
+
56
+ path = Path.for(path, *args)
57
+
58
+ fragment = options.delete(:fragment)
59
+ query = options.delete(:query) || options
60
+
61
+ uri = URI.parse(base.to_s)
62
+ uri.path = Path.for(uri.path, path).absolute
63
+ uri.path = '' if uri.path == '/'
64
+
65
+ uri.query = query_string_for(query) unless query.empty?
66
+
67
+ uri.fragment = fragment if fragment
68
+
69
+ uri.to_s
70
+ end
71
+
72
+ def query_string_for(hash, options = {})
73
+ options = Map.for(options)
74
+ escape = options.has_key?(:escape) ? options[:escape] : true
75
+ pairs = []
76
+ esc = escape ? proc { |v| CGI.escape(v.to_s) } : proc { |v| v.to_s }
77
+ hash.each do |key, values|
78
+ key = key.to_s
79
+ values = [values].flatten
80
+ values.each do |value|
81
+ value = value.to_s
82
+ pairs << if value.empty?
83
+ [esc[key]]
84
+ else
85
+ [esc[key], esc[value]].join('=')
86
+ end
87
+ end
88
+ end
89
+ pairs.replace(pairs.sort_by { |pair| pair.size })
90
+ pairs.join('&')
91
+ end
92
+
93
+ def normalize_url(url)
94
+ uri = URI.parse(url.to_s).normalize
95
+ uri.path = Path.for(uri.path).absolute
96
+ uri.to_s
97
+ end
98
+
99
+ # log methods
100
+ # |
101
+ # v
102
+ attr_accessor :logger
103
+
104
+ def log(*args, &block)
105
+ level = nil
106
+
107
+ level = if args.size == 0 || args.size == 1
108
+ :info
109
+ else
110
+ args.shift.to_s.to_sym
111
+ end
112
+
113
+ @logger && @logger.send(level, *args, &block)
114
+ end
115
+
116
+ def log!
117
+ Ro.logger =
118
+ ::Logger.new(STDERR).tap do |logger|
119
+ logger.level = ::Logger::INFO
120
+ end
121
+ end
122
+
123
+ def debug!
124
+ Ro.logger =
125
+ ::Logger.new(STDERR).tap do |logger|
126
+ logger.level = ::Logger::DEBUG
127
+ end
128
+ end
129
+
130
+ def error!(message, context = nil)
131
+ error = Error.new(message, context)
132
+
133
+ begin
134
+ raise error
135
+ rescue Error
136
+ backtrace = error.backtrace || []
137
+ error.set_backtrace(backtrace[1..-1])
138
+ raise
139
+ end
140
+ end
141
+
142
+ # template methods
143
+ # |
144
+ # v
145
+ def template(method = :tap, *args, &block)
146
+ Template.send(method, *args, &(block || proc {}))
147
+ end
148
+
149
+ def render(path, context = nil)
150
+ Template.render(path, context:)
151
+ end
152
+
153
+ def render_src(path, context = nil)
154
+ Template.render_src(path, context:)
155
+ end
156
+
157
+ # asset expansion methods
158
+ # |
159
+ # v
160
+ EXPAND_ASSET_URL_STRATEGIES = %i[
161
+ accurate_expand_asset_urls sloppy_expand_asset_urls
162
+ ]
163
+
164
+ def expand_asset_url_strategies
165
+ @expand_asset_url_strategies ||= EXPAND_ASSET_URL_STRATEGIES.dup
166
+ end
167
+
168
+ def expand_asset_urls(html, node)
169
+ last = expand_asset_url_strategies.size - 1
170
+
171
+ expand_asset_url_strategies.each_with_index do |strategy, i|
172
+ return send(strategy, html, node)
173
+ rescue Object => e
174
+ raise if i == last
175
+
176
+ Ro.log(e)
177
+ end
178
+
179
+ Ro.error! "could not expand assets via #{expand_asset_url_strategies.join(' | ')}"
180
+ end
181
+
182
+ def accurate_expand_asset_urls(html, node)
183
+ doc = REXML::Document.new('<__ro__>' + html + '</__ro__>')
184
+
185
+ doc.each_recursive do |element|
186
+ next unless element.respond_to?(:attributes)
187
+
188
+ src = {}
189
+ element.attributes.each do |key, value|
190
+ src[key] = value
191
+ end
192
+
193
+ dst = expand_asset_values(src, node)
194
+
195
+ dst.each do |k, v|
196
+ element.attributes[k] = v
197
+ end
198
+ end
199
+
200
+ doc.to_s.tap do |xml|
201
+ xml.sub!(/^\s*<.?__ro__>\s*/, '')
202
+ xml.sub!(/\s*<.?__ro__>\s*$/, '')
203
+ xml.strip!
204
+ end
205
+ end
206
+
207
+ def sloppy_expand_asset_urls(html, node)
208
+ html.to_s.gsub(%r{\s*=\s*['"](?:[.]/)?assets/[^'"\s]+['"]}) do |match|
209
+ path = match[%r{assets/[^'"\s]+}]
210
+ url = node.url_for(path)
211
+ "='#{url}'"
212
+ end
213
+ end
214
+
215
+ def expand_asset_values(hash, node)
216
+ src = Map.for(hash)
217
+ dst = Map.new
218
+
219
+ re = %r{\A(?:[.]/)?(assets/[^\s]+)\s*\z}
220
+
221
+ src.depth_first_each do |key, value|
222
+ next unless value.is_a?(String)
223
+
224
+ if (match = re.match(value.strip))
225
+ path = match[1].strip
226
+ url = node.url_for(path)
227
+ value = url
228
+ end
229
+
230
+ dst.set(key, value)
231
+ end
232
+
233
+ dst.to_hash
234
+ end
235
+ end
236
+
237
+ extend Methods
238
+ end
data/lib/ro/model.rb CHANGED
@@ -1,97 +1,113 @@
1
1
  begin
2
2
  require 'active_model'
3
3
  require 'active_support'
4
- require 'active_support/core_ext/string/inflections.rb'
4
+ require 'active_support/core_ext/string/inflections'
5
5
  rescue LoadError => e
6
6
  abort "you need to add the 'active_model' and 'active_support' gems to use Ro::Model"
7
7
  end
8
8
 
9
+ require_relative '../ro' unless defined?(Ro)
10
+
9
11
  module Ro
10
12
  class Model
11
- #
13
+ require_relative 'pagination'
14
+
12
15
  extend ActiveModel::Naming
13
16
  extend ActiveModel::Translation
14
17
  include ActiveModel::Validations
15
18
  include ActiveModel::Conversion
16
19
 
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) }
20
+ class << Model
21
+ def root
22
+ @root ||= Ro.root
23
+ end
22
24
 
23
- def Model.nodes(*args, &block)
24
- root.nodes.send(collection)
25
- end
25
+ def root=(root)
26
+ @root = Ro::Root.for(root)
27
+ end
26
28
 
27
- def Model.all(*args, &block)
28
- models_for(nodes)
29
- end
29
+ def default_collection_name
30
+ name.to_s.split(/::/).last.underscore.pluralize
31
+ end
30
32
 
31
- def Model.select(*args, &block)
32
- all.select(*args, &block)
33
- end
33
+ def collection_name(collection_name = nil)
34
+ @collection_name = collection_name.to_s if collection_name
34
35
 
35
- def Model.detect(*args, &block)
36
- all.detect(*args, &block)
37
- end
36
+ @collection_name || default_collection_name
37
+ end
38
38
 
39
- def Model.count(*args, &block)
40
- if args.empty? and block.nil?
41
- all.size
42
- else
43
- where(*args, &block).size
39
+ def collection
40
+ root.collections[collection_name]
44
41
  end
45
- end
46
42
 
47
- def Model.where(*args, &block)
48
- all.select do |model|
49
- !!model.instance_eval(&block)
43
+ def nodes
44
+ collection.to_a
50
45
  end
51
- end
52
46
 
53
- def Model.first
54
- all.first
55
- end
47
+ def all
48
+ models_for(nodes)
49
+ end
56
50
 
57
- def Model.last
58
- all.last
59
- end
51
+ def select(*args, &block)
52
+ all.select(*args, &block)
53
+ end
60
54
 
61
- def Model.find(id)
62
- re = %r/#{ id.to_s.gsub(/[-_]/, '[-_]') }/i
63
- all.detect{|model| model.id.to_s == id.to_s}
64
- end
55
+ def detect(*args, &block)
56
+ all.detect(*args, &block)
57
+ end
65
58
 
66
- def Model.[](id)
67
- find(id)
68
- end
59
+ def count(*args, &block)
60
+ if args.empty? and block.nil?
61
+ all.size
62
+ else
63
+ where(*args, &block).size
64
+ end
65
+ end
69
66
 
70
- def Model.method_missing(method, *args, &block)
71
- id = method
72
- model = find(id)
73
- return model if model
74
- super
75
- end
67
+ def where(*_args, &block)
68
+ all.select do |model|
69
+ !!model.instance_eval(&block)
70
+ end
71
+ end
72
+
73
+ def first
74
+ all.first
75
+ end
76
+
77
+ def last
78
+ all.last
79
+ end
76
80
 
77
- def Model.models_for(result)
78
- case result
81
+ def find(id)
82
+ slug = Slug.for(id)
83
+ all.detect { |model| Slug.for(model.id) == slug }
84
+ end
85
+
86
+ def [](id)
87
+ find(id)
88
+ end
89
+
90
+ def models_for(result)
91
+ case result
79
92
  when Array
80
- List.for(Array(result).flatten.compact.map{|element| new(element)})
93
+ List.for(Array(result).flatten.compact.map { |element| new(element) })
81
94
  else
82
95
  new(result)
96
+ end
83
97
  end
84
- end
85
98
 
86
- def Model.paginate(*args, &block)
87
- all.paginate(*args, &block)
99
+ def paginate(*args, &block)
100
+ all.paginate(*args, &block)
101
+ end
88
102
  end
89
103
 
90
104
  class List < ::Array
91
105
  include Pagination
92
106
 
93
- def List.for(*args, &block)
94
- new(*args, &block)
107
+ class << List
108
+ def for(*args, &block)
109
+ new(*args, &block)
110
+ end
95
111
  end
96
112
 
97
113
  def select(*args, &block)
@@ -107,26 +123,17 @@ module Ro
107
123
  List.new(*args, &block)
108
124
  end
109
125
 
110
- #
111
126
  attr_accessor(:node)
112
127
 
113
- def initialize(*args, &block)
128
+ def initialize(*args)
114
129
  attributes = Map.options_for!(args)
115
130
 
116
- node = args.detect{|arg| arg.is_a?(Node)}
117
- model = args.detect{|arg| arg.is_a?(Model)}
131
+ node = args.detect { |arg| arg.is_a?(Node) }
132
+ model = args.detect { |arg| arg.is_a?(Model) }
118
133
 
119
- if node.nil? and not model.nil?
120
- node = model.node
121
- end
134
+ node = model.node if node.nil? and !model.nil?
122
135
 
123
- if node
124
- @node = node
125
- else
126
- path = File.join(prefix, ':new')
127
- node = Node.new(path)
128
- @node = node
129
- end
136
+ @node = node
130
137
  end
131
138
 
132
139
  def attributes
@@ -137,54 +144,16 @@ module Ro
137
144
  true
138
145
  end
139
146
 
140
- #
141
- def prefix
142
- self.class.prefix
143
- end
144
-
145
- def directory
146
- File.join(prefix, id)
147
- end
148
-
149
- #
150
147
  def method_missing(method, *args, &block)
151
- node.send(method, *args, &block)
148
+ begin
149
+ node.send(method, *args, &block)
150
+ rescue
151
+ super
152
+ end
152
153
  end
153
154
 
154
- def respond_to?(method)
155
+ def respond_to?(method, *args, &block)
155
156
  super || node.respond_to?(method)
156
157
  end
157
158
  end
158
159
  end
159
-
160
-
161
-
162
-
163
- if __FILE__ == $0
164
-
165
- ENV['RO_ROOT'] = '../sample_ro_data'
166
-
167
- class Person < Ro::Model
168
-
169
- #field(:first_name, :type => :string)
170
-
171
- end
172
-
173
- p Person.collection
174
- p Person.all
175
- p Person.find(:ara).attributes
176
- ara = Person.find(:ara)
177
-
178
- p ara.url_for(:ara_glacier)
179
-
180
- p Person.paginate(:per => 2, :page => 1)
181
- p Person.name
182
-
183
- p Person.prefix
184
- p ara.id
185
- p ara.first_name
186
-
187
- require 'pry'
188
- binding.pry
189
-
190
- end