roger 1.1.3 → 1.2.1
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.
- checksums.yaml +4 -4
- data/.hound.yml +2 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +1 -5
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -3
- data/Rakefile +10 -4
- data/bin/roger +1 -1
- data/doc/mockupfile.md +97 -0
- data/doc/templating.md +5 -1
- data/examples/default_template/Gemfile +1 -1
- data/lib/roger/cli.rb +41 -36
- data/lib/roger/cli/command.rb +2 -4
- data/lib/roger/cli/generate.rb +1 -0
- data/lib/roger/cli/release.rb +2 -2
- data/lib/roger/cli/serve.rb +11 -11
- data/lib/roger/cli/test.rb +6 -5
- data/lib/roger/extractor.rb +42 -43
- data/lib/roger/generators.rb +27 -19
- data/lib/roger/generators/generator.rb +7 -10
- data/lib/roger/generators/new.rb +56 -41
- data/lib/roger/generators/templates/generator.tt +5 -5
- data/lib/roger/helpers/get_callable.rb +15 -14
- data/lib/roger/helpers/logging.rb +35 -13
- data/lib/roger/mockupfile.rb +13 -23
- data/lib/roger/project.rb +41 -34
- data/lib/roger/rack/roger.rb +28 -29
- data/lib/roger/rack/sleep.rb +4 -5
- data/lib/roger/release.rb +95 -72
- data/lib/roger/release/cleaner.rb +14 -13
- data/lib/roger/release/finalizers.rb +10 -10
- data/lib/roger/release/finalizers/dir.rb +17 -19
- data/lib/roger/release/finalizers/git_branch.rb +76 -38
- data/lib/roger/release/finalizers/rsync.rb +60 -49
- data/lib/roger/release/finalizers/zip.rb +32 -29
- data/lib/roger/release/injector.rb +43 -37
- data/lib/roger/release/processors.rb +24 -22
- data/lib/roger/release/processors/mockup.rb +97 -69
- data/lib/roger/release/processors/url_relativizer.rb +57 -30
- data/lib/roger/release/scm.rb +30 -27
- data/lib/roger/release/scm/git.rb +101 -92
- data/lib/roger/resolver.rb +86 -61
- data/lib/roger/server.rb +52 -27
- data/lib/roger/template.rb +102 -74
- data/lib/roger/test.rb +16 -13
- data/lib/roger/version.rb +3 -2
- data/roger.gemspec +9 -5
- data/test/helpers/cli.rb +17 -15
- data/test/project/Gemfile +2 -2
- data/test/project/html/formats/csv.rcsv +0 -0
- data/test/project/lib/generators/test.rb +2 -3
- data/test/project/lib/tests/fail/fail.rb +5 -6
- data/test/project/lib/tests/noop/lib/cli.rb +2 -1
- data/test/project/lib/tests/noop/lib/test.rb +5 -5
- data/test/project/lib/tests/noop/noop.rb +2 -1
- data/test/project/lib/tests/succeed/succeed.rb +5 -6
- data/test/unit/cli/cli_base_test.rb +2 -3
- data/test/unit/cli/cli_generate_test.rb +9 -10
- data/test/unit/cli/cli_serve_test.rb +22 -18
- data/test/unit/cli/cli_test_test.rb +13 -15
- data/test/unit/cli/cli_version_test.rb +4 -4
- data/test/unit/generators_test.rb +8 -10
- data/test/unit/helpers/logging_test.rb +64 -0
- data/test/unit/rack/roger_test.rb +21 -0
- data/test/unit/release/cleaner_test.rb +23 -19
- data/test/unit/release/finalizers/git_branch_test.rb +2 -1
- data/test/unit/release/finalizers/zip_test.rb +48 -0
- data/test/unit/release/mockup_test.rb +48 -0
- data/test/unit/release/processors_test.rb +19 -19
- data/test/unit/release_test.rb +15 -14
- data/test/unit/resolver_test.rb +21 -14
- data/test/unit/server_test.rb +31 -0
- data/test/unit/template_test.rb +58 -36
- data/test/unit/test_test.rb +3 -2
- metadata +35 -9
- data/test/Mockupfile-syntax.rb +0 -93
data/lib/roger/server.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
require
|
1
|
+
require "rack"
|
2
2
|
require File.dirname(__FILE__) + "/template"
|
3
3
|
require File.dirname(__FILE__) + "/rack/roger"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "webrick"
|
6
|
+
require "webrick/https"
|
7
7
|
|
8
8
|
module Roger
|
9
|
+
# The Roger webserver. Initializes a rack server.
|
9
10
|
class Server
|
10
|
-
|
11
11
|
attr_reader :server_options
|
12
12
|
|
13
13
|
attr_reader :project
|
14
14
|
|
15
15
|
attr_accessor :port, :handler, :host
|
16
16
|
|
17
|
-
def initialize(project, options={})
|
18
|
-
@stack = initialize_rack_builder
|
19
|
-
|
17
|
+
def initialize(project, options = {})
|
20
18
|
@project = project
|
21
19
|
|
20
|
+
@stack = initialize_rack_builder
|
21
|
+
|
22
22
|
@server_options = {}
|
23
23
|
|
24
24
|
# Defaults
|
@@ -32,28 +32,28 @@ module Roger
|
|
32
32
|
# Sets the options, this is a separate method as we want to override certain
|
33
33
|
# things set in the mockupfile from the commandline
|
34
34
|
def set_options(options)
|
35
|
-
self.port = options[:port] if options.
|
36
|
-
self.handler = options[:handler] if options.
|
37
|
-
self.host = options[:host] if options.
|
35
|
+
self.port = options[:port] if options.key?(:port)
|
36
|
+
self.handler = options[:handler] if options.key?(:handler)
|
37
|
+
self.host = options[:host] if options.key?(:host)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Use the specified Rack middleware
|
41
41
|
#
|
42
42
|
# @see ::Rack::Builder#use
|
43
43
|
def use(*args, &block)
|
44
|
-
@stack.use
|
44
|
+
@stack.use(*args, &block)
|
45
45
|
end
|
46
46
|
|
47
47
|
# Use the map handler to map endpoints to certain urls
|
48
48
|
#
|
49
49
|
# @see ::Rack::Builder#map
|
50
50
|
def map(*args, &block)
|
51
|
-
@stack.map
|
51
|
+
@stack.map(*args, &block)
|
52
52
|
end
|
53
53
|
|
54
54
|
def run!
|
55
55
|
project.mode = :server
|
56
|
-
|
56
|
+
handler.run application, server_options do |server|
|
57
57
|
trap(:INT) do
|
58
58
|
## Use thins' hard #stop! if available, otherwise just #stop
|
59
59
|
server.respond_to?(:stop!) ? server.stop! : server.stop
|
@@ -63,21 +63,21 @@ module Roger
|
|
63
63
|
ensure
|
64
64
|
project.mode = nil
|
65
65
|
end
|
66
|
-
|
66
|
+
alias_method :run, :run!
|
67
67
|
|
68
68
|
def port=(p)
|
69
|
-
@port =
|
69
|
+
@port = server_options[:Port] = p
|
70
70
|
end
|
71
71
|
|
72
72
|
def host=(h)
|
73
|
-
@host =
|
73
|
+
@host = server_options[:Host] = h
|
74
74
|
end
|
75
75
|
|
76
76
|
def handler=(h)
|
77
77
|
if h.respond_to?(:run)
|
78
78
|
@handler = h
|
79
79
|
else
|
80
|
-
@handler =
|
80
|
+
@handler = get_handler(h)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -87,7 +87,7 @@ module Roger
|
|
87
87
|
def application
|
88
88
|
return @app if @app
|
89
89
|
|
90
|
-
@stack.run Rack::Roger.new(
|
90
|
+
@stack.run Rack::Roger.new(project)
|
91
91
|
|
92
92
|
@app = @stack
|
93
93
|
end
|
@@ -96,7 +96,25 @@ module Roger
|
|
96
96
|
#
|
97
97
|
# @return ::Rack::Builder instance
|
98
98
|
def initialize_rack_builder
|
99
|
+
roger_env = Class.new do
|
100
|
+
class << self
|
101
|
+
attr_accessor :project
|
102
|
+
end
|
103
|
+
|
104
|
+
def initialize(app)
|
105
|
+
@app = app
|
106
|
+
end
|
107
|
+
|
108
|
+
def call(env)
|
109
|
+
env["roger.project"] = self.class.project
|
110
|
+
@app.call(env)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
roger_env.project = project
|
115
|
+
|
99
116
|
builder = ::Rack::Builder.new
|
117
|
+
builder.use roger_env
|
100
118
|
builder.use ::Rack::ShowExceptions
|
101
119
|
builder.use ::Rack::Lint
|
102
120
|
builder.use ::Rack::ConditionalGet
|
@@ -108,23 +126,30 @@ module Roger
|
|
108
126
|
# Get the actual handler for use in the server
|
109
127
|
# Will always return a handler, it will try to use the fallbacks
|
110
128
|
def get_handler(preferred_handler_name = nil)
|
111
|
-
servers = %w
|
129
|
+
servers = %w(puma mongrel thin webrick)
|
112
130
|
servers.unshift(preferred_handler_name) if preferred_handler_name
|
113
131
|
|
132
|
+
handler, server_name = detect_valid_handler(servers)
|
133
|
+
|
134
|
+
if preferred_handler_name && server_name != preferred_handler_name
|
135
|
+
puts "Handler '#{preferred_handler_name}' not found, using fallback ('#{handler.inspect}')."
|
136
|
+
end
|
137
|
+
handler
|
138
|
+
end
|
139
|
+
|
140
|
+
# See what handlers work
|
141
|
+
def detect_valid_handler(servers)
|
114
142
|
handler = nil
|
115
|
-
while(
|
143
|
+
while (server_name = servers.shift) && handler.nil?
|
116
144
|
begin
|
117
145
|
handler = ::Rack::Handler.get(server_name)
|
146
|
+
return [handler, server_name]
|
118
147
|
rescue LoadError
|
148
|
+
handler = nil
|
119
149
|
rescue NameError
|
150
|
+
handler = nil
|
120
151
|
end
|
121
152
|
end
|
122
|
-
|
123
|
-
if preferred_handler_name && server_name != preferred_handler_name
|
124
|
-
puts "Handler '#{preferred_handler_name}' not found, using fallback ('#{handler.inspect}')."
|
125
|
-
end
|
126
|
-
handler
|
127
153
|
end
|
128
|
-
|
129
154
|
end
|
130
|
-
end
|
155
|
+
end
|
data/lib/roger/template.rb
CHANGED
@@ -1,56 +1,53 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "tilt"
|
2
|
+
require "mime/types"
|
3
|
+
require "yaml"
|
4
|
+
require "ostruct"
|
5
5
|
|
6
6
|
# We're enforcing Encoding to UTF-8
|
7
7
|
Encoding.default_external = "UTF-8"
|
8
8
|
|
9
9
|
module Roger
|
10
|
-
|
10
|
+
# Roger template processing class
|
11
11
|
class Template
|
12
|
-
|
13
12
|
# The source
|
14
13
|
attr_accessor :source
|
15
|
-
|
14
|
+
|
16
15
|
# Store the frontmatter
|
17
16
|
attr_accessor :data
|
18
|
-
|
17
|
+
|
19
18
|
# The actual Tilt template
|
20
19
|
attr_accessor :template
|
21
|
-
|
20
|
+
|
22
21
|
# The path to the source file for this template
|
23
22
|
attr_accessor :source_path
|
24
|
-
|
23
|
+
|
25
24
|
class << self
|
26
25
|
def open(path, options = {})
|
27
|
-
|
28
|
-
|
29
|
-
end
|
26
|
+
fail "Unknown file #{path}" unless File.exist?(path)
|
27
|
+
new(File.read(path), options.update(source_path: path))
|
28
|
+
end
|
30
29
|
end
|
31
|
-
|
32
|
-
|
33
|
-
#
|
30
|
+
|
31
|
+
# @option options [String,Pathname] :source_path The path to
|
32
|
+
# the source of the template being processed
|
34
33
|
# @option options [String,Pathname] :layouts_path The path to where all layouts reside
|
35
|
-
# @option options [String,Pathname] :partials_path The path to where all partials reside
|
34
|
+
# @option options [String,Pathname] :partials_path The path to where all partials reside
|
36
35
|
def initialize(source, options = {})
|
37
36
|
@options = options
|
38
37
|
|
39
38
|
self.source_path = options[:source_path]
|
40
39
|
self.data, self.source = extract_front_matter(source)
|
41
|
-
self.template = Tilt.new(
|
42
|
-
|
43
|
-
|
44
|
-
@layout_template = Tilt.new(layout_template_path.to_s)
|
45
|
-
end
|
40
|
+
self.template = Tilt.new(source_path.to_s) { self.source }
|
41
|
+
|
42
|
+
initialize_layout
|
46
43
|
end
|
47
|
-
|
44
|
+
|
48
45
|
def render(env = {})
|
49
46
|
context = TemplateContext.new(self, env)
|
50
|
-
|
47
|
+
|
51
48
|
if @layout_template
|
52
|
-
content_for_layout =
|
53
|
-
|
49
|
+
content_for_layout = template.render(context, {}) # yields
|
50
|
+
|
54
51
|
@layout_template.render(context, {}) do |content_for|
|
55
52
|
if content_for
|
56
53
|
context._content_for_blocks[content_for]
|
@@ -59,26 +56,28 @@ module Roger
|
|
59
56
|
end
|
60
57
|
end
|
61
58
|
else
|
62
|
-
|
59
|
+
template.render(context, {})
|
63
60
|
end
|
64
61
|
end
|
65
|
-
|
62
|
+
|
66
63
|
def find_template(name, path_type)
|
67
|
-
|
64
|
+
unless [:partials_path, :layouts_path].include?(path_type)
|
65
|
+
fail(ArgumentError, "path_type must be one of :partials_path or :layouts_path")
|
66
|
+
end
|
68
67
|
|
69
68
|
return nil unless @options[path_type]
|
70
69
|
|
71
|
-
@resolvers ||= {}
|
70
|
+
@resolvers ||= {}
|
72
71
|
@resolvers[path_type] ||= Resolver.new(@options[path_type])
|
73
|
-
|
74
|
-
@resolvers[path_type].find_template(name, :
|
72
|
+
|
73
|
+
@resolvers[path_type].find_template(name, preferred_extension: target_extension)
|
75
74
|
end
|
76
75
|
|
77
76
|
# Try to infer the final extension of the output file.
|
78
77
|
def target_extension
|
79
78
|
return @target_extension if @target_extension
|
80
79
|
|
81
|
-
if type = MIME::Types[
|
80
|
+
if type = MIME::Types[target_mime_type].first
|
82
81
|
# Dirty little hack to enforce the use of .html instead of .htm
|
83
82
|
if type.sub_type == "html"
|
84
83
|
@target_extension = "html"
|
@@ -86,49 +85,68 @@ module Roger
|
|
86
85
|
@target_extension = type.extensions.first
|
87
86
|
end
|
88
87
|
else
|
89
|
-
@target_extension = File.extname(
|
88
|
+
@target_extension = File.extname(source_path.to_s).sub(/^\./, "")
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
93
92
|
def source_extension
|
94
|
-
parts = File.basename(File.basename(
|
93
|
+
parts = File.basename(File.basename(source_path.to_s)).split(".")
|
95
94
|
if parts.size > 2
|
96
95
|
parts[-2..-1].join(".")
|
97
96
|
else
|
98
|
-
File.extname(
|
97
|
+
File.extname(source_path.to_s).sub(/^\./, "")
|
99
98
|
end
|
100
99
|
end
|
101
100
|
|
102
101
|
# Try to figure out the mime type based on the Tilt class and if that doesn't
|
103
102
|
# work we try to infer the type by looking at extensions (needed for .erb)
|
104
103
|
def target_mime_type
|
105
|
-
mime =
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
mime = MIME::Types.type_for(path).first
|
110
|
-
return mime.to_s if mime
|
104
|
+
mime =
|
105
|
+
mime_type_from_template ||
|
106
|
+
mime_type_from_filename ||
|
107
|
+
mime_type_from_sub_extension
|
111
108
|
|
112
|
-
|
113
|
-
if parts.size > 2
|
114
|
-
mime = MIME::Types.type_for(parts[0..-2].join(".")).first
|
115
|
-
return mime.to_s if mime
|
116
|
-
else
|
117
|
-
nil
|
118
|
-
end
|
109
|
+
mime.to_s if mime
|
119
110
|
end
|
120
|
-
|
111
|
+
|
121
112
|
protected
|
122
113
|
|
114
|
+
def initialize_layout
|
115
|
+
return unless data[:layout]
|
116
|
+
layout_template_path = find_template(data[:layout], :layouts_path)
|
117
|
+
|
118
|
+
@layout_template = Tilt.new(layout_template_path.to_s) if layout_template_path
|
119
|
+
end
|
120
|
+
|
121
|
+
def mime_type_from_template
|
122
|
+
template.class.default_mime_type
|
123
|
+
end
|
124
|
+
|
125
|
+
def mime_type_from_filename
|
126
|
+
path = File.basename(source_path.to_s)
|
127
|
+
MIME::Types.type_for(path).first
|
128
|
+
end
|
129
|
+
|
130
|
+
# Will get mime_type from source_path extension
|
131
|
+
# but it will only look at the second extension so
|
132
|
+
# .html.erb will look at .html
|
133
|
+
def mime_type_from_sub_extension
|
134
|
+
parts = File.basename(source_path.to_s).split(".")
|
135
|
+
MIME::Types.type_for(parts[0..-2].join(".")).first if parts.size > 2
|
136
|
+
end
|
137
|
+
|
123
138
|
# Get the front matter portion of the file and extract it.
|
124
139
|
def extract_front_matter(source)
|
125
140
|
fm_regex = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
126
|
-
|
141
|
+
|
127
142
|
if match = source.match(fm_regex)
|
128
143
|
source = source.sub(fm_regex, "")
|
129
144
|
|
130
145
|
begin
|
131
|
-
data = (YAML.load(match[1]) || {}).inject({})
|
146
|
+
data = (YAML.load(match[1]) || {}).inject({}) do |memo, (k, v)|
|
147
|
+
memo[k.to_sym] = v
|
148
|
+
memo
|
149
|
+
end
|
132
150
|
rescue *YAML_ERRORS => e
|
133
151
|
puts "YAML Exception: #{e.message}"
|
134
152
|
return false
|
@@ -141,20 +159,21 @@ module Roger
|
|
141
159
|
rescue
|
142
160
|
[{}, source]
|
143
161
|
end
|
144
|
-
|
145
162
|
end
|
146
|
-
|
163
|
+
|
164
|
+
# The context that is passed to all templates
|
147
165
|
class TemplateContext
|
148
166
|
attr_accessor :_content_for_blocks
|
149
167
|
|
150
|
-
def initialize(template, env={})
|
168
|
+
def initialize(template, env = {})
|
151
169
|
@_content_for_blocks = {}
|
152
|
-
@_template
|
170
|
+
@_template = template
|
171
|
+
@_env = env
|
153
172
|
|
154
173
|
# Block counter to make sure erbtemp binding is always unique
|
155
174
|
@block_counter = 0
|
156
175
|
end
|
157
|
-
|
176
|
+
|
158
177
|
# The current Roger::Template in use
|
159
178
|
def template
|
160
179
|
@_template
|
@@ -162,9 +181,9 @@ module Roger
|
|
162
181
|
|
163
182
|
# Access to the front-matter of the document (if any)
|
164
183
|
def document
|
165
|
-
@_data ||= OpenStruct.new(
|
184
|
+
@_data ||= OpenStruct.new(template.data)
|
166
185
|
end
|
167
|
-
|
186
|
+
|
168
187
|
# The current environment variables.
|
169
188
|
def env
|
170
189
|
@_env
|
@@ -186,40 +205,49 @@ module Roger
|
|
186
205
|
@_content_for_blocks[block_name] = capture(&block)
|
187
206
|
end
|
188
207
|
|
208
|
+
# rubocop:disable Lint/Eval
|
189
209
|
def capture(&block)
|
190
|
-
|
210
|
+
unless template.template.is_a?(Tilt::ERBTemplate)
|
211
|
+
fail ArgumentError, "content_for works only with ERB Templates"
|
212
|
+
end
|
191
213
|
|
192
214
|
@block_counter += 1
|
193
215
|
counter = @block_counter
|
194
216
|
|
195
217
|
eval "@_erbout_tmp#{counter} = _erbout", block.binding
|
196
218
|
eval "_erbout = \"\"", block.binding
|
197
|
-
t = Tilt::ERBTemplate.new
|
219
|
+
t = Tilt::ERBTemplate.new { "<%= yield %>" }
|
198
220
|
t.render(&block)
|
199
221
|
ensure
|
200
222
|
eval "_erbout = @_erbout_tmp#{counter}", block.binding
|
201
223
|
end
|
202
|
-
|
203
|
-
def partial(name, options = {}, &block)
|
204
|
-
if template_path = self.template.find_template(name, :partials_path)
|
205
|
-
partial_template = Tilt.new(template_path.to_s)
|
206
|
-
if block_given?
|
207
|
-
block_content = capture(&block)
|
208
|
-
else
|
209
|
-
block_content = ""
|
210
|
-
end
|
211
|
-
out = partial_template.render(self, options[:locals] || {}){ block_content }
|
212
224
|
|
225
|
+
def partial(name, options = {}, &block)
|
226
|
+
template_path = template.find_template(name, :partials_path)
|
227
|
+
if template_path
|
228
|
+
out = render_partial(template_path, options, &block)
|
213
229
|
if block_given?
|
214
230
|
eval "_erbout.concat(#{out.dump})", block.binding
|
215
231
|
else
|
216
232
|
out
|
217
233
|
end
|
218
234
|
else
|
219
|
-
|
235
|
+
fail ArgumentError, "No such partial #{name}, referenced from #{template.source_path}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
# rubocop:enable Lint/Eval
|
239
|
+
|
240
|
+
protected
|
241
|
+
|
242
|
+
# Capture a block and render the partial
|
243
|
+
def render_partial(template_path, options, &block)
|
244
|
+
partial_template = Tilt.new(template_path.to_s)
|
245
|
+
if block_given?
|
246
|
+
block_content = capture(&block)
|
247
|
+
else
|
248
|
+
block_content = ""
|
220
249
|
end
|
250
|
+
partial_template.render(self, options[:locals] || {}) { block_content }
|
221
251
|
end
|
222
|
-
|
223
252
|
end
|
224
|
-
|
225
253
|
end
|