roger 1.1.3 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|