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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +2 -0
  3. data/.rubocop.yml +47 -0
  4. data/.travis.yml +1 -5
  5. data/CHANGELOG.md +8 -0
  6. data/Gemfile +3 -3
  7. data/Rakefile +10 -4
  8. data/bin/roger +1 -1
  9. data/doc/mockupfile.md +97 -0
  10. data/doc/templating.md +5 -1
  11. data/examples/default_template/Gemfile +1 -1
  12. data/lib/roger/cli.rb +41 -36
  13. data/lib/roger/cli/command.rb +2 -4
  14. data/lib/roger/cli/generate.rb +1 -0
  15. data/lib/roger/cli/release.rb +2 -2
  16. data/lib/roger/cli/serve.rb +11 -11
  17. data/lib/roger/cli/test.rb +6 -5
  18. data/lib/roger/extractor.rb +42 -43
  19. data/lib/roger/generators.rb +27 -19
  20. data/lib/roger/generators/generator.rb +7 -10
  21. data/lib/roger/generators/new.rb +56 -41
  22. data/lib/roger/generators/templates/generator.tt +5 -5
  23. data/lib/roger/helpers/get_callable.rb +15 -14
  24. data/lib/roger/helpers/logging.rb +35 -13
  25. data/lib/roger/mockupfile.rb +13 -23
  26. data/lib/roger/project.rb +41 -34
  27. data/lib/roger/rack/roger.rb +28 -29
  28. data/lib/roger/rack/sleep.rb +4 -5
  29. data/lib/roger/release.rb +95 -72
  30. data/lib/roger/release/cleaner.rb +14 -13
  31. data/lib/roger/release/finalizers.rb +10 -10
  32. data/lib/roger/release/finalizers/dir.rb +17 -19
  33. data/lib/roger/release/finalizers/git_branch.rb +76 -38
  34. data/lib/roger/release/finalizers/rsync.rb +60 -49
  35. data/lib/roger/release/finalizers/zip.rb +32 -29
  36. data/lib/roger/release/injector.rb +43 -37
  37. data/lib/roger/release/processors.rb +24 -22
  38. data/lib/roger/release/processors/mockup.rb +97 -69
  39. data/lib/roger/release/processors/url_relativizer.rb +57 -30
  40. data/lib/roger/release/scm.rb +30 -27
  41. data/lib/roger/release/scm/git.rb +101 -92
  42. data/lib/roger/resolver.rb +86 -61
  43. data/lib/roger/server.rb +52 -27
  44. data/lib/roger/template.rb +102 -74
  45. data/lib/roger/test.rb +16 -13
  46. data/lib/roger/version.rb +3 -2
  47. data/roger.gemspec +9 -5
  48. data/test/helpers/cli.rb +17 -15
  49. data/test/project/Gemfile +2 -2
  50. data/test/project/html/formats/csv.rcsv +0 -0
  51. data/test/project/lib/generators/test.rb +2 -3
  52. data/test/project/lib/tests/fail/fail.rb +5 -6
  53. data/test/project/lib/tests/noop/lib/cli.rb +2 -1
  54. data/test/project/lib/tests/noop/lib/test.rb +5 -5
  55. data/test/project/lib/tests/noop/noop.rb +2 -1
  56. data/test/project/lib/tests/succeed/succeed.rb +5 -6
  57. data/test/unit/cli/cli_base_test.rb +2 -3
  58. data/test/unit/cli/cli_generate_test.rb +9 -10
  59. data/test/unit/cli/cli_serve_test.rb +22 -18
  60. data/test/unit/cli/cli_test_test.rb +13 -15
  61. data/test/unit/cli/cli_version_test.rb +4 -4
  62. data/test/unit/generators_test.rb +8 -10
  63. data/test/unit/helpers/logging_test.rb +64 -0
  64. data/test/unit/rack/roger_test.rb +21 -0
  65. data/test/unit/release/cleaner_test.rb +23 -19
  66. data/test/unit/release/finalizers/git_branch_test.rb +2 -1
  67. data/test/unit/release/finalizers/zip_test.rb +48 -0
  68. data/test/unit/release/mockup_test.rb +48 -0
  69. data/test/unit/release/processors_test.rb +19 -19
  70. data/test/unit/release_test.rb +15 -14
  71. data/test/unit/resolver_test.rb +21 -14
  72. data/test/unit/server_test.rb +31 -0
  73. data/test/unit/template_test.rb +58 -36
  74. data/test/unit/test_test.rb +3 -2
  75. metadata +35 -9
  76. data/test/Mockupfile-syntax.rb +0 -93
@@ -1,24 +1,24 @@
1
- require 'rack'
1
+ require "rack"
2
2
  require File.dirname(__FILE__) + "/template"
3
3
  require File.dirname(__FILE__) + "/rack/roger"
4
4
 
5
- require 'webrick'
6
- require 'webrick/https'
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.has_key?(:port)
36
- self.handler = options[:handler] if options.has_key?(:handler)
37
- self.host = options[:host] if options.has_key?(:host)
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 *args, &block
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 *args, &block
51
+ @stack.map(*args, &block)
52
52
  end
53
53
 
54
54
  def run!
55
55
  project.mode = :server
56
- self.handler.run self.application, self.server_options do |server|
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
- alias :run :run!
66
+ alias_method :run, :run!
67
67
 
68
68
  def port=(p)
69
- @port = self.server_options[:Port] = p
69
+ @port = server_options[:Port] = p
70
70
  end
71
71
 
72
72
  def host=(h)
73
- @host = self.server_options[:Host] = h
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 = self.get_handler(h)
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(self.project)
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[puma mongrel thin webrick]
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((server_name = servers.shift) && handler === nil) do
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
@@ -1,56 +1,53 @@
1
- require 'tilt'
2
- require 'mime/types'
3
- require 'yaml'
4
- require 'ostruct'
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
- raise "Unknown file #{path}" unless File.exist?(path)
28
- self.new(File.read(path), options.update(:source_path => path))
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
- # @option options [String,Pathname] :source_path The path to the source of the template being processed
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(self.source_path.to_s){ self.source }
42
-
43
- if self.data[:layout] && layout_template_path = self.find_template(self.data[:layout], :layouts_path)
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 = self.template.render(context, {}) # yields
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
- self.template.render(context, {})
59
+ template.render(context, {})
63
60
  end
64
61
  end
65
-
62
+
66
63
  def find_template(name, path_type)
67
- raise(ArgumentError, "path_type must be one of :partials_path or :layouts_path") unless [:partials_path, :layouts_path].include?(path_type)
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, :preferred_extension => self.target_extension)
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[self.target_mime_type].first
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(self.source_path.to_s).sub(/^\./, "")
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(self.source_path.to_s)).split(".")
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(self.source_path.to_s).sub(/^\./, "")
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 = self.template.class.default_mime_type
106
- return mime if mime
107
-
108
- path = File.basename(self.source_path.to_s)
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
- parts = File.basename(path).split(".")
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({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
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, @_env = template, env
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(self.template.data)
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
- raise ArgumentError, "content_for works only with ERB Templates" if !self.template.template.kind_of?(Tilt::ERBTemplate)
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(){ "<%= yield %>" }
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
- raise ArgumentError, "No such partial #{name}, referenced from #{self.template.source_path}"
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