ro 1.4.6 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/Gemfile +2 -0
- data/Gemfile.lock +43 -0
- data/LICENSE +1 -0
- data/README.md +120 -112
- data/README.md.erb +159 -0
- data/Rakefile +129 -78
- data/bin/ro +241 -68
- data/lib/ro/_lib.rb +95 -0
- data/lib/ro/asset.rb +45 -0
- data/lib/ro/collection/list.rb +23 -0
- data/lib/ro/collection.rb +168 -0
- data/lib/ro/config.rb +68 -0
- data/lib/ro/error.rb +8 -0
- data/lib/ro/klass.rb +25 -0
- data/lib/ro/methods.rb +238 -0
- data/lib/ro/model.rb +83 -114
- data/lib/ro/node.rb +177 -360
- data/lib/ro/pagination.rb +7 -4
- data/lib/ro/path.rb +225 -0
- data/lib/ro/root.rb +52 -31
- data/lib/ro/script/builder.rb +221 -0
- data/lib/ro/script/console.rb +47 -0
- data/lib/ro/script/server.rb +76 -0
- data/lib/ro/script.rb +189 -0
- data/lib/ro/slug.rb +19 -18
- data/lib/ro/template/rouge_formatter.rb +42 -0
- data/lib/ro/template.rb +104 -50
- data/lib/ro.rb +85 -317
- data/public/api/ro/index-1.json +147 -0
- data/public/api/ro/index.json +137 -0
- data/public/api/ro/posts/first_post/index.json +52 -0
- data/public/api/ro/posts/index-1.json +145 -0
- data/public/api/ro/posts/index.json +135 -0
- data/public/api/ro/posts/second_post/index.json +51 -0
- data/public/api/ro/posts/third_post/index.json +51 -0
- data/public/ro/posts/first_post/assets/foo/bar/baz.jpg +0 -0
- data/public/ro/posts/first_post/assets/foo.jpg +0 -0
- data/public/ro/posts/first_post/assets/src/foo/bar.rb +3 -0
- data/public/ro/posts/first_post/attributes.yml +2 -0
- data/public/ro/posts/first_post/blurb.erb.md +7 -0
- data/public/ro/posts/first_post/body.md +16 -0
- data/public/ro/posts/first_post/testing.txt +3 -0
- data/public/ro/posts/second_post/assets/foo/bar/baz.jpg +0 -0
- data/public/ro/posts/second_post/assets/foo.jpg +0 -0
- data/public/ro/posts/second_post/assets/src/foo/bar.rb +3 -0
- data/public/ro/posts/second_post/attributes.yml +2 -0
- data/public/ro/posts/second_post/blurb.erb.md +5 -0
- data/public/ro/posts/second_post/body.md +16 -0
- data/public/ro/posts/third_post/assets/foo/bar/baz.jpg +0 -0
- data/public/ro/posts/third_post/assets/foo.jpg +0 -0
- data/public/ro/posts/third_post/assets/src/foo/bar.rb +3 -0
- data/public/ro/posts/third_post/attributes.yml +2 -0
- data/public/ro/posts/third_post/blurb.erb.md +5 -0
- data/public/ro/posts/third_post/body.md +16 -0
- data/ro.gemspec +89 -29
- metadata +106 -90
- data/TODO.md +0 -50
- data/lib/ro/blankslate.rb +0 -7
- data/lib/ro/cache.rb +0 -26
- data/lib/ro/git.rb +0 -374
- data/lib/ro/initializers/env.rb +0 -5
- data/lib/ro/initializers/tilt.rb +0 -104
- data/lib/ro/lock.rb +0 -53
- data/lib/ro/node/list.rb +0 -142
- data/notes/ara.txt +0 -215
data/lib/ro/path.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Ro
|
4
|
+
class Path < ::String
|
5
|
+
include Klass
|
6
|
+
|
7
|
+
class << Path
|
8
|
+
def clean(arg, *args)
|
9
|
+
Pathname.new([arg, *args].join('/')).cleanpath.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def expand(arg, *args)
|
13
|
+
new(Pathname.new(clean(arg, *args).expand_path))
|
14
|
+
end
|
15
|
+
|
16
|
+
def absolute(...)
|
17
|
+
new(...).absolute
|
18
|
+
end
|
19
|
+
|
20
|
+
def absolute?(arg, *args)
|
21
|
+
Path.for(arg, *args).absolute?
|
22
|
+
end
|
23
|
+
|
24
|
+
def relative(...)
|
25
|
+
new(...).relative
|
26
|
+
end
|
27
|
+
|
28
|
+
def relative?(arg, *args)
|
29
|
+
Path.for(arg, *args).relative?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(arg, *args)
|
34
|
+
super Path.clean(arg, *args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def pn
|
38
|
+
Pathname.new(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
def klass
|
42
|
+
self.class
|
43
|
+
end
|
44
|
+
|
45
|
+
{
|
46
|
+
'exist?' => 'exist?',
|
47
|
+
'file?' => 'file?',
|
48
|
+
'directory?' => 'directory?',
|
49
|
+
'absolute?' => 'absolute?',
|
50
|
+
'relative?' => 'relative?',
|
51
|
+
'expand' => 'expand_path',
|
52
|
+
'clean' => 'cleanpath'
|
53
|
+
}.each do |path_method, pathname_method|
|
54
|
+
class_eval <<-____, __FILE__, __LINE__ + 1
|
55
|
+
|
56
|
+
def #{ path_method }(...)
|
57
|
+
result = pn.#{ pathname_method }(...)
|
58
|
+
|
59
|
+
result.is_a?(Pathname) ? klass.for(result) : result
|
60
|
+
end
|
61
|
+
|
62
|
+
____
|
63
|
+
end
|
64
|
+
|
65
|
+
def absolute
|
66
|
+
Path.new('/' + self)
|
67
|
+
end
|
68
|
+
|
69
|
+
def relative
|
70
|
+
Path.new(absolute.gsub(%r{^/+}, ''))
|
71
|
+
end
|
72
|
+
|
73
|
+
def parts
|
74
|
+
parts = scan(%r`[^/]+`)
|
75
|
+
|
76
|
+
if absolute?
|
77
|
+
%w[ / ] + parts
|
78
|
+
else
|
79
|
+
parts
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def key
|
84
|
+
parts
|
85
|
+
end
|
86
|
+
|
87
|
+
def relative_to(other)
|
88
|
+
a = Pathname.new(self).expand_path
|
89
|
+
b = Pathname.new(other).expand_path
|
90
|
+
Path.for(a.relative_path_from(b))
|
91
|
+
end
|
92
|
+
|
93
|
+
def relative_from(...)
|
94
|
+
relative_to(...)
|
95
|
+
end
|
96
|
+
|
97
|
+
def relative_to!(other)
|
98
|
+
a = Pathname.new(self).realpath
|
99
|
+
b = Pathname.new(other).realpath
|
100
|
+
|
101
|
+
Path.for(a.relative_path_from(b))
|
102
|
+
end
|
103
|
+
|
104
|
+
def glob(arg = '**/**', *args, **kws, &block)
|
105
|
+
glob = Path.for(self, arg, *args, **kws)
|
106
|
+
|
107
|
+
accum = []
|
108
|
+
|
109
|
+
Dir.glob(glob) do |entry|
|
110
|
+
path = Path.new(entry)
|
111
|
+
block ? block.call(path) : accum.push(path)
|
112
|
+
end
|
113
|
+
|
114
|
+
accum
|
115
|
+
end
|
116
|
+
alias ls glob
|
117
|
+
|
118
|
+
def files(arg = '**/**', *args, **kws, &block)
|
119
|
+
glob = Path.for(self, arg, *args, **kws)
|
120
|
+
|
121
|
+
accum = []
|
122
|
+
|
123
|
+
Dir.glob(glob) do |entry|
|
124
|
+
next unless test(?f, entry)
|
125
|
+
path = Path.new(entry)
|
126
|
+
block ? block.call(path) : accum.push(path)
|
127
|
+
end
|
128
|
+
|
129
|
+
accum
|
130
|
+
end
|
131
|
+
|
132
|
+
def select(&block)
|
133
|
+
glob.select(&block)
|
134
|
+
end
|
135
|
+
|
136
|
+
def detect(&block)
|
137
|
+
glob.detect(&block)
|
138
|
+
end
|
139
|
+
|
140
|
+
def parent
|
141
|
+
Path.for(File.dirname(self))
|
142
|
+
end
|
143
|
+
alias dirname parent
|
144
|
+
|
145
|
+
def basename
|
146
|
+
Path.for(File.basename(self))
|
147
|
+
end
|
148
|
+
alias name basename
|
149
|
+
|
150
|
+
def base
|
151
|
+
base, ext = basename.split('.', 2)
|
152
|
+
base
|
153
|
+
end
|
154
|
+
|
155
|
+
def extension
|
156
|
+
base, ext = basename.split('.', 2)
|
157
|
+
ext
|
158
|
+
end
|
159
|
+
alias ext extension
|
160
|
+
|
161
|
+
def join(arg, *args)
|
162
|
+
Path.for(self, Path.clean(arg, *args))
|
163
|
+
end
|
164
|
+
|
165
|
+
def binwrite(data)
|
166
|
+
FileUtils.mkdir_p(dirname)
|
167
|
+
IO.binwrite(self, data)
|
168
|
+
end
|
169
|
+
|
170
|
+
def sibling?(other)
|
171
|
+
expand.dirname == Path.for(other).expand.dirname
|
172
|
+
end
|
173
|
+
|
174
|
+
def child?(other)
|
175
|
+
parent = expand
|
176
|
+
child = Path.for(other).expand
|
177
|
+
(parent.size < child.size && child.start_with?(parent))
|
178
|
+
end
|
179
|
+
|
180
|
+
def parent?(other)
|
181
|
+
child = expand
|
182
|
+
parent = Path.for(other).expand
|
183
|
+
(parent.size < child.size && child.start_with?(parent))
|
184
|
+
end
|
185
|
+
|
186
|
+
def file?
|
187
|
+
test(?f, self)
|
188
|
+
end
|
189
|
+
|
190
|
+
def directory?
|
191
|
+
test(?d, self)
|
192
|
+
end
|
193
|
+
|
194
|
+
def subdirectories(&block)
|
195
|
+
accum = []
|
196
|
+
|
197
|
+
glob('*') do |entry|
|
198
|
+
next unless entry.directory?
|
199
|
+
block ? block.call(entry) : accum.push(entry)
|
200
|
+
end
|
201
|
+
|
202
|
+
block ? self : accum
|
203
|
+
end
|
204
|
+
alias subdirs subdirectories
|
205
|
+
|
206
|
+
def subdirectory_for(subdirectory)
|
207
|
+
join(Path.relative(subdirectory))
|
208
|
+
end
|
209
|
+
alias subdir_for subdirectory_for
|
210
|
+
|
211
|
+
def subdirectory?(subdirectory)
|
212
|
+
subdirectory = join(Path.relative(subdirectory))
|
213
|
+
subdirectory.exist?
|
214
|
+
end
|
215
|
+
alias subdir? subdirectory?
|
216
|
+
|
217
|
+
def sort_key
|
218
|
+
[dirname.to_s, basename.to_s]
|
219
|
+
end
|
220
|
+
|
221
|
+
def <=>(other)
|
222
|
+
sort_key <=> other.sort_key
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
data/lib/ro/root.rb
CHANGED
@@ -1,52 +1,73 @@
|
|
1
1
|
module Ro
|
2
|
-
class Root <
|
3
|
-
def
|
4
|
-
super(Ro.realpath(root.to_s))
|
5
|
-
ensure
|
6
|
-
raise ArgumentError.new("root=#{ root.inspect }") if root.nil?
|
7
|
-
raise ArgumentError.new("root=#{ root.inspect }") unless test(?d, self)
|
8
|
-
end
|
9
|
-
|
10
|
-
def root
|
2
|
+
class Root < Path
|
3
|
+
def identifier
|
11
4
|
self
|
12
5
|
end
|
13
6
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
def collections(&block)
|
8
|
+
accum = Collection::List.for(self)
|
9
|
+
|
10
|
+
subdirectories do |subdirectory|
|
11
|
+
collection = collection_for(subdirectory)
|
12
|
+
block ? block.call(collection) : accum.push(collection)
|
19
13
|
end
|
20
|
-
end
|
21
14
|
|
22
|
-
|
23
|
-
Dir.glob(File.join(root, '*/'), &block)
|
15
|
+
block ? self : accum
|
24
16
|
end
|
25
17
|
|
26
|
-
def
|
27
|
-
|
18
|
+
def collection_for(subdirectory)
|
19
|
+
Collection.new(subdirectory)
|
28
20
|
end
|
29
21
|
|
30
|
-
def
|
31
|
-
|
22
|
+
def paths_for(name)
|
23
|
+
[
|
24
|
+
subdirectory_for(name),
|
25
|
+
subdirectory_for(Slug.for(name, :join => '-')),
|
26
|
+
subdirectory_for(Slug.for(name, :join => '_')),
|
27
|
+
]
|
32
28
|
end
|
33
29
|
|
34
|
-
def
|
35
|
-
|
30
|
+
def get(name)
|
31
|
+
name = name.to_s
|
32
|
+
|
33
|
+
if name.index('/')
|
34
|
+
collection_name, node_name = name.split('/', 2)
|
35
|
+
collection = get(collection_name)
|
36
|
+
|
37
|
+
if collection
|
38
|
+
node = collection.get(node_name)
|
39
|
+
return node
|
40
|
+
else
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
paths_for(name).each do |path|
|
46
|
+
next unless path.directory?
|
47
|
+
return collection_for(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
nil
|
36
51
|
end
|
37
52
|
|
38
|
-
def
|
39
|
-
|
53
|
+
def [](name)
|
54
|
+
get(name)
|
40
55
|
end
|
41
56
|
|
42
|
-
def
|
43
|
-
|
57
|
+
def nodes(&block)
|
58
|
+
accum = []
|
59
|
+
|
60
|
+
collections.each do |collection|
|
61
|
+
collection.nodes do |node|
|
62
|
+
block ? block.call(node) : accum.push(node)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
block ? self : accum
|
44
67
|
end
|
45
68
|
|
46
|
-
def
|
47
|
-
|
48
|
-
@lock ||= Lock.new(lockpath)
|
49
|
-
block ? @lock.lock(&block) : @lock
|
69
|
+
def method_missing(name, *args, **kws, &block)
|
70
|
+
get(name) || super
|
50
71
|
end
|
51
72
|
end
|
52
73
|
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
module Ro
|
2
|
+
class Script::Builder
|
3
|
+
class << self
|
4
|
+
def run!(...)
|
5
|
+
new(...).run!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(script:)
|
10
|
+
@script = script
|
11
|
+
end
|
12
|
+
|
13
|
+
def run!
|
14
|
+
@url = Ro.config.url
|
15
|
+
@root = Ro.config.root
|
16
|
+
@directory = Ro.config.build
|
17
|
+
@page_size = Ro.config.page_size
|
18
|
+
@collections = Ro.root.collections.sort_by(&:name)
|
19
|
+
|
20
|
+
@build = {}
|
21
|
+
@nodes = []
|
22
|
+
|
23
|
+
@started_at = Time.now.to_f
|
24
|
+
@finished_at = nil
|
25
|
+
@elapsed = nil
|
26
|
+
|
27
|
+
# for all node collections...
|
28
|
+
#
|
29
|
+
@collections.each do |collection|
|
30
|
+
type = collection.type
|
31
|
+
name = collection.name
|
32
|
+
nodes = nodes_for(collection)
|
33
|
+
|
34
|
+
count = nodes.size
|
35
|
+
last = count - 1
|
36
|
+
page_count = (count / @page_size.to_f).ceil
|
37
|
+
paginator = paginator_for(page_count, @page_size)
|
38
|
+
|
39
|
+
nodes.each_with_index do |node, index|
|
40
|
+
@nodes << node
|
41
|
+
id = node.id
|
42
|
+
|
43
|
+
# enhance with links to next/prev
|
44
|
+
#
|
45
|
+
rel = rel_for(nodes, index)
|
46
|
+
node.attributes[:_meta][:rel] = rel
|
47
|
+
|
48
|
+
# node data
|
49
|
+
#
|
50
|
+
data = data_for(node)
|
51
|
+
_meta = meta_for(type:, id:)
|
52
|
+
path = "#{type}/#{id}/index.json"
|
53
|
+
@build[path] = { data:, _meta: }
|
54
|
+
|
55
|
+
# paginate data
|
56
|
+
#
|
57
|
+
paginator[:data].push(node)
|
58
|
+
generate_page = ((paginator[:data].size == paginator[:size]) || (index == last))
|
59
|
+
next unless generate_page
|
60
|
+
|
61
|
+
page = page_for(paginator)
|
62
|
+
data = data_for(paginator[:data])
|
63
|
+
_meta = meta_for(type:, page:)
|
64
|
+
pageno = page[:index] + 1
|
65
|
+
path = "#{type}/index-#{pageno}.json" # eg. posts/page-$pageno.json
|
66
|
+
@build[path] = { data:, _meta: }
|
67
|
+
|
68
|
+
paginator[:data].clear
|
69
|
+
paginator[:index] += 1
|
70
|
+
end
|
71
|
+
|
72
|
+
data = data_for(nodes)
|
73
|
+
_meta = meta_for(type:)
|
74
|
+
path = "#{type}/index.json" # eg. posts/index.json
|
75
|
+
@build[path] = { data:, _meta: }
|
76
|
+
end
|
77
|
+
|
78
|
+
# annnnd for all nodes...
|
79
|
+
#
|
80
|
+
count = @nodes.size
|
81
|
+
last = count - 1
|
82
|
+
page_count = (count / @page_size.to_f).ceil
|
83
|
+
paginator = paginator_for(page_count, @page_size)
|
84
|
+
|
85
|
+
@nodes.each_with_index do |node, index|
|
86
|
+
# enhance with links to next/prev
|
87
|
+
#
|
88
|
+
rel = rel_for(@nodes, index)
|
89
|
+
node.attributes[:_meta][:rel] = rel
|
90
|
+
|
91
|
+
paginator[:data].push(node)
|
92
|
+
should_generate_page = ((paginator[:data].size == paginator[:size]) || (index == last))
|
93
|
+
next unless should_generate_page
|
94
|
+
|
95
|
+
types = paginator[:data].map(&:type).sort.uniq
|
96
|
+
page = page_for(paginator)
|
97
|
+
data = data_for(paginator[:data])
|
98
|
+
_meta = meta_for(types:, page:)
|
99
|
+
|
100
|
+
pageno = page[:index] + 1
|
101
|
+
path = "index-#{pageno}.json" # eg. page-$pageno.json
|
102
|
+
@build[path] = { data:, _meta: }
|
103
|
+
|
104
|
+
paginator[:data].clear
|
105
|
+
paginator[:index] += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
# index.json
|
109
|
+
#
|
110
|
+
types = @collections.map(&:type).sort
|
111
|
+
data = data_for(@nodes)
|
112
|
+
_meta = meta_for(types:)
|
113
|
+
path = 'index.json'
|
114
|
+
@build[path] = { data:, _meta: }
|
115
|
+
|
116
|
+
# now output the build
|
117
|
+
#
|
118
|
+
@script.say("ro.build: #{@root} -> #{@directory}", color: :magenta)
|
119
|
+
|
120
|
+
FileUtils.rm_rf(@directory)
|
121
|
+
FileUtils.mkdir_p(File.dirname(@directory))
|
122
|
+
#FileUtils.cp_r(@root, @directory)
|
123
|
+
|
124
|
+
Ro::Path.for(@directory).glob('**/**') do |entry|
|
125
|
+
next unless test('f', entry)
|
126
|
+
|
127
|
+
@script.say("ro.build: #{entry}", color: :blue)
|
128
|
+
end
|
129
|
+
|
130
|
+
@build.each do |subpath, data|
|
131
|
+
path = Ro::Path.for(@directory, subpath)
|
132
|
+
@script.say("ro.build: #{path}", color: :yellow)
|
133
|
+
Ro.error! "#{path} would be clobbered" if path.exist?
|
134
|
+
|
135
|
+
if data.is_a?(String)
|
136
|
+
path.binwrite(data)
|
137
|
+
else
|
138
|
+
path.binwrite(JSON.pretty_generate(data))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# show stats
|
143
|
+
#
|
144
|
+
@finished_at = Time.now.to_f
|
145
|
+
@elapsed = (@finished_at - @started_at).round(2)
|
146
|
+
|
147
|
+
@script.say("ro.build: #{@root} -> #{@directory} in #{@elapsed}s", color: :green)
|
148
|
+
end
|
149
|
+
|
150
|
+
def global_meta
|
151
|
+
{ url: @url }
|
152
|
+
end
|
153
|
+
|
154
|
+
def meta_for(meta)
|
155
|
+
global_meta.merge(meta)
|
156
|
+
end
|
157
|
+
|
158
|
+
def rel_for(list, index)
|
159
|
+
{ curr: list[index].identifier, prev: nil, next: nil }.tap do |rel|
|
160
|
+
rel[:prev] = list[index - 1].identifier if (index - 1) >= 0
|
161
|
+
rel[:next] = list[index + 1].identifier if (index + 1) <= (list.size - 1)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def paginator_for(count, size)
|
166
|
+
{
|
167
|
+
count:,
|
168
|
+
size:,
|
169
|
+
first: 0,
|
170
|
+
last: count - 1,
|
171
|
+
index: 0,
|
172
|
+
data: []
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def page_for(paginator)
|
177
|
+
paginator.except(:data).merge(
|
178
|
+
{
|
179
|
+
curr: paginator[:index],
|
180
|
+
prev: ((paginator[:index] - 1) >= paginator[:first] ? (paginator[:index] - 1) : nil),
|
181
|
+
next: ((paginator[:index] + 1) <= paginator[:last] ? (paginator[:index] + 1) : nil)
|
182
|
+
}
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
def data_for(value)
|
187
|
+
{}.tap do |hash|
|
188
|
+
case value
|
189
|
+
when Array
|
190
|
+
value.each { |node| hash.update(data_for(node)) }
|
191
|
+
when Ro::Node
|
192
|
+
hash[value.identifier] = value.to_hash
|
193
|
+
else
|
194
|
+
raise ArgumentError, "#{value.class}(#{value.inspect})"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def nodes_for(list)
|
200
|
+
filtered_nodes_for(sorted_nodes_for(list))
|
201
|
+
end
|
202
|
+
|
203
|
+
def sorted_nodes_for(list)
|
204
|
+
list.to_a.sort
|
205
|
+
end
|
206
|
+
|
207
|
+
def filtered_nodes_for(list)
|
208
|
+
list.select { |node| select_node?(node) }
|
209
|
+
end
|
210
|
+
|
211
|
+
def select_node?(node)
|
212
|
+
now = Time.now.utc
|
213
|
+
|
214
|
+
hidden = Ro.cast(:bool, node.attributes.fetch(:hidden) { false })
|
215
|
+
published = Ro.cast(:bool, node.attributes.fetch(:published) { true })
|
216
|
+
published_at = Ro.cast(:time, node.attributes.fetch(:published_at) { now.iso8601 })
|
217
|
+
|
218
|
+
((not hidden) && (published) && (published_at <= now))
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ro
|
2
|
+
class Script::Console
|
3
|
+
class << self
|
4
|
+
def run!(...)
|
5
|
+
new(...).run!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(script:)
|
10
|
+
@script = script
|
11
|
+
end
|
12
|
+
|
13
|
+
def run!
|
14
|
+
$A_GIANT_FUCKING_HACK_FOR_IBB = ARGV.clear
|
15
|
+
|
16
|
+
require 'irb'
|
17
|
+
|
18
|
+
$GIANT_FUCKING_HACK = IRB.method(:load_modules)
|
19
|
+
|
20
|
+
Kernel.module_eval do
|
21
|
+
def ro
|
22
|
+
Ro.root
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def IRB.load_modules
|
27
|
+
$GIANT_FUCKING_HACK.call
|
28
|
+
|
29
|
+
prompt = "ro[./#{Ro.root.relative_to(Dir.pwd)}]"
|
30
|
+
|
31
|
+
IRB.conf[:PROMPT][:RO] = {
|
32
|
+
PROMPT_I: "#{prompt}:%03n:%i> ",
|
33
|
+
PROMPT_N: "#{prompt}:%03n:%i> ",
|
34
|
+
PROMPT_S: "#{prompt}:%03n:%i%l ",
|
35
|
+
PROMPT_C: "#{prompt}:%03n:%i* ",
|
36
|
+
RETURN: "=> %s\n"
|
37
|
+
|
38
|
+
}
|
39
|
+
|
40
|
+
IRB.conf[:PROMPT_MODE] = :RO
|
41
|
+
IRB.conf[:AUTO_INDENT] = true
|
42
|
+
end
|
43
|
+
|
44
|
+
::IRB.start
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Ro
|
2
|
+
class Script::Server
|
3
|
+
class << self
|
4
|
+
def run!(...)
|
5
|
+
new(...).run!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(script:)
|
10
|
+
@script = script
|
11
|
+
|
12
|
+
@port = @script.opts.fetch(:port)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run!
|
16
|
+
Ro.config.set(:url, server_url)
|
17
|
+
|
18
|
+
#build!
|
19
|
+
|
20
|
+
threads = [watcher!, server!]
|
21
|
+
|
22
|
+
trap('INT') do
|
23
|
+
threads.each do |thread|
|
24
|
+
thread.kill
|
25
|
+
rescue StandardError
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
|
31
|
+
sleep
|
32
|
+
end
|
33
|
+
|
34
|
+
def server_url
|
35
|
+
build = Ro.config.build
|
36
|
+
document_root = build.dirname
|
37
|
+
path_info = build.relative_to(document_root)
|
38
|
+
Ro.normalize_url("http://localhost:#{@port}/#{path_info}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def build!
|
42
|
+
system "RO_URL=#{Ro.config.url} RO_ROOT=#{Ro.config.root} ro build"
|
43
|
+
end
|
44
|
+
|
45
|
+
def watcher!
|
46
|
+
Thread.new do
|
47
|
+
Thread.current.abort_on_exception = true
|
48
|
+
system "RO_URL=#{Ro.config.url} RO_ROOT=#{Ro.config.root} ro build --watch"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def server!
|
53
|
+
require 'webrick'
|
54
|
+
|
55
|
+
build = Ro.config.build
|
56
|
+
document_root = build.dirname
|
57
|
+
|
58
|
+
index_url = File.join(server_url, 'index.json')
|
59
|
+
|
60
|
+
@script.say("ro.server: @ #{index_url}", color: :magenta)
|
61
|
+
|
62
|
+
Thread.new do
|
63
|
+
Thread.current.abort_on_exception = true
|
64
|
+
|
65
|
+
server = WEBrick::HTTPServer.new(
|
66
|
+
DocumentRoot: document_root,
|
67
|
+
Port: @port
|
68
|
+
)
|
69
|
+
|
70
|
+
::Kernel.at_exit { server.shutdown }
|
71
|
+
|
72
|
+
server.start
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|