flatrack 1.3.3 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +3 -6
  5. data/flatrack.gemspec +4 -3
  6. data/lib/custom-extensions/sprockets-sass.rb +32 -0
  7. data/lib/flatrack.rb +123 -11
  8. data/lib/flatrack/asset_extensions.rb +7 -1
  9. data/lib/flatrack/cli.rb +9 -1
  10. data/lib/flatrack/domain_parser.rb +13 -0
  11. data/lib/flatrack/middleware.rb +32 -0
  12. data/lib/flatrack/redirector.rb +63 -0
  13. data/lib/flatrack/request.rb +16 -2
  14. data/lib/flatrack/response.rb +7 -8
  15. data/lib/flatrack/rewriter.rb +32 -0
  16. data/lib/flatrack/sass/functions.rb +6 -6
  17. data/lib/flatrack/sass/importer.rb +7 -7
  18. data/lib/flatrack/sass/sass_template.rb +6 -6
  19. data/lib/flatrack/site.rb +2 -27
  20. data/lib/flatrack/template.rb +27 -8
  21. data/lib/flatrack/template/erubis.rb +2 -2
  22. data/lib/flatrack/template/html.rb +2 -2
  23. data/lib/flatrack/template/rb.rb +2 -2
  24. data/lib/flatrack/version.rb +1 -1
  25. data/lib/flatrack/view.rb +1 -1
  26. data/lib/flatrack/view/capture_helper.rb +1 -2
  27. data/lib/flatrack/view/link_helper.rb +8 -1
  28. data/lib/flatrack/view/render_helper.rb +1 -1
  29. data/lib/flatrack/view/request_helper.rb +23 -2
  30. data/lib/flatrack/view/tag_helper.rb +19 -11
  31. data/spec/lib/flatrack/cli_spec.rb +28 -2
  32. data/spec/lib/flatrack/middleware_spec.rb +55 -0
  33. data/spec/lib/flatrack/site_spec.rb +3 -5
  34. data/spec/lib/flatrack/view/render_helper_spec.rb +4 -0
  35. data/spec/lib/flatrack/view/set_layout_spec.rb +1 -1
  36. data/spec/lib/flatrack/view/tag_helper_spec.rb +9 -0
  37. data/spec/lib/flatrack/view_spec.rb +1 -1
  38. data/spec/lib/flatrack_spec.rb +73 -0
  39. data/spec/lib/rake/asset_tasks_spec.rb +2 -2
  40. data/spec/spec_helper.rb +1 -0
  41. data/spec/support/fixture_helper.rb +1 -1
  42. data/spec/support/site_helper.rb +3 -1
  43. metadata +32 -9
@@ -13,6 +13,10 @@ class Flatrack
13
13
 
14
14
  # the path of the incoming request
15
15
  def path
16
+ env['ORIGINAL_PATH_INFO'] || env['PATH_INFO']
17
+ end
18
+
19
+ def page
16
20
  env['PATH_INFO']
17
21
  end
18
22
 
@@ -33,12 +37,22 @@ class Flatrack
33
37
  # the processed response for an inbound request
34
38
  def response
35
39
  Response.new(self).render
36
- rescue TemplateNotFound
40
+ rescue TemplateNotFound => e
41
+ raise e if config.raise_errors
37
42
  respond_with_error(500)
38
- rescue FileNotFound
43
+ rescue FileNotFound => e
44
+ raise e if config.raise_errors
39
45
  respond_with_error(404)
40
46
  end
41
47
 
48
+ def config
49
+ env['flatrack.config']
50
+ end
51
+
52
+ def mount_path
53
+ env['SCRIPT_NAME'].present? ? env['SCRIPT_NAME'] : '/'
54
+ end
55
+
42
56
  private
43
57
 
44
58
  def respond_with_error(code)
@@ -6,7 +6,7 @@ class Flatrack
6
6
 
7
7
  attr_accessor :layout
8
8
  attr_reader :request
9
- delegate :format, to: :request
9
+ delegate :mount_path, :config, :format, to: :request
10
10
 
11
11
  # Initializes a response
12
12
  # @param request [Flatrack::Request]
@@ -20,7 +20,7 @@ class Flatrack
20
20
  # @option opts [Fixnum] :status
21
21
  # @option opts [Symbol] :layout
22
22
  # @return [Array] the rack response
23
- def render(file: file_for(request.path), status: 200, layout: :layout)
23
+ def render(file: file_for(request.page), status: 200, layout: :layout)
24
24
  @file, @status, @layout = file, status, layout
25
25
  page_content = pre_render_page
26
26
  body << begin
@@ -57,19 +57,18 @@ class Flatrack
57
57
  end
58
58
 
59
59
  def file_for(path)
60
- if File.directory?(File.join 'pages', path)
61
- File.join(path, DEFAULT_FILE)
62
- else
63
- path
60
+ if File.directory?(File.join config.site_root, 'pages', path)
61
+ path = File.join(path, DEFAULT_FILE)
64
62
  end
63
+ path
65
64
  end
66
65
 
67
66
  def renderer_for_page(file)
68
- Template.find :page, format, file
67
+ Template.find config.site_root, :page, format, file
69
68
  end
70
69
 
71
70
  def renderer_for_layout(file)
72
- Template.find :layout, format, file
71
+ Template.find config.site_root, :layout, format, file
73
72
  end
74
73
 
75
74
  def view
@@ -0,0 +1,32 @@
1
+ class Flatrack
2
+ def Rewriter(source, opts={})
3
+ to = opts.delete(:to)
4
+ klass = Class.new(Rewriter)
5
+ klass.send(:define_method, :initialize) do |app, mw_opts|
6
+ mapping = { source => to }
7
+ super app, mapping, mw_opts
8
+ end
9
+ klass
10
+ end
11
+
12
+ class Rewriter
13
+
14
+ def initialize(app, mapping = {}, opts = {})
15
+ @if = opts[:if] || Proc.new { true }
16
+ @unless = opts[:unless] || Proc.new { false }
17
+ @app = app
18
+ @mapping =
19
+ Hash[mapping.map { |paths| paths.map { |p| File.join '', p } }]
20
+ end
21
+
22
+ def call(env)
23
+ allow = @if.call(env) && !@unless.call(env)
24
+ if allow && @mapping.keys.include?(env['PATH_INFO'])
25
+ env['ORIGINAL_PATH_INFO'] = env['PATH_INFO']
26
+ env['PATH_INFO'] = @mapping[env['PATH_INFO']]
27
+ end
28
+ @app.call env
29
+ end
30
+
31
+ end
32
+ end
@@ -148,16 +148,16 @@ module Sass::Script::Functions
148
148
  defined?(@signatures) && @signatures.delete(method)
149
149
  end
150
150
 
151
- declare :asset_path, [:source], :var_kwargs => true
151
+ declare :asset_path, [:source], var_kwargs: true
152
152
  declare :asset_path, [:source, :kind]
153
- declare :asset_url, [:source], :var_kwargs => true
153
+ declare :asset_url, [:source], var_kwargs: true
154
154
  declare :asset_url, [:source, :kind]
155
- declare :image_path, [:source], :var_kwargs => true
156
- declare :image_url, [:source], :var_kwargs => true
155
+ declare :image_path, [:source], var_kwargs: true
156
+ declare :image_url, [:source], var_kwargs: true
157
157
  declare :image_url, [:source, :only_path]
158
158
  declare :image_url, [:source, :only_path, :cache_buster]
159
- declare :font_path, [:source], :var_kwargs => true
160
- declare :font_url, [:source], :var_kwargs => true
159
+ declare :font_path, [:source], var_kwargs: true
160
+ declare :font_url, [:source], var_kwargs: true
161
161
  declare :font_url, [:source, :only_path]
162
162
  declare :asset_data_uri, [:source]
163
163
  end
@@ -48,9 +48,9 @@ class Flatrack
48
48
  pathname = resolve(context, path, base_path) or return nil
49
49
  context.depend_on pathname
50
50
  ::Sass::Engine.new evaluate(context, pathname), options.merge(
51
- :filename => pathname.to_s,
52
- :syntax => syntax(pathname),
53
- :importer => self
51
+ filename: pathname.to_s,
52
+ syntax: syntax(pathname),
53
+ importer: self
54
54
  )
55
55
  end
56
56
 
@@ -65,9 +65,9 @@ class Flatrack
65
65
  end
66
66
  return nil if imports.empty?
67
67
  ::Sass::Engine.new imports, options.merge(
68
- :filename => base_path.to_s,
69
- :syntax => :scss,
70
- :importer => self
68
+ filename: base_path.to_s,
69
+ syntax: :scss,
70
+ importer: self
71
71
  )
72
72
  end
73
73
 
@@ -135,7 +135,7 @@ class Flatrack
135
135
  attributes = context.environment.attributes_for(path)
136
136
  processors = context.environment.preprocessors(attributes.content_type) + attributes.engines.reverse
137
137
  processors.delete_if { |processor| processor < Tilt::SassTemplate }
138
- context.evaluate(path, :processors => processors)
138
+ context.evaluate(path, processors: processors)
139
139
  end
140
140
  end
141
141
  end
@@ -66,12 +66,12 @@ class Flatrack
66
66
  # Assemble the options for the `Sass::Engine`
67
67
  def sass_options
68
68
  merge_sass_options(default_sass_options, options).merge(
69
- :filename => eval_file,
70
- :line => line,
71
- :syntax => syntax,
72
- :cache_store => cache_store,
73
- :importer => Importer.new,
74
- :custom => { :sprockets_context => context }
69
+ filename: eval_file,
70
+ line: line,
71
+ syntax: syntax,
72
+ cache_store: cache_store,
73
+ importer: Importer.new,
74
+ custom: { sprockets_context: context }
75
75
  )
76
76
  end
77
77
 
@@ -3,32 +3,7 @@ require 'rack/server'
3
3
  class Flatrack
4
4
  # Provides a rake wrapper for encapsulating a flatrack site
5
5
  module Site
6
- # Call the site with a rack env
7
- # @param env [Hash] the rack env
8
- def self.call(env)
9
- builder.call(env)
10
- end
11
-
12
- private
13
-
14
- def self.builder
15
- mapping = self.mapping
16
- Rack::Builder.app do
17
- use Rack::Static, urls: ['/favicon.ico', 'assets'], root: 'public'
18
- Flatrack.middleware.each { |mw| use(*mw) }
19
- mapping.each { |path, app| map(path) { run app } }
20
- end
21
- end
22
-
23
- def self.site
24
- ->(env) { Request.new(env).response }
25
- end
26
-
27
- def self.mapping
28
- {
29
- '/assets' => Flatrack.assets,
30
- '/' => site
31
- }
32
- end
6
+ extend self
7
+ delegate :call, to: Flatrack
33
8
  end
34
9
  end
@@ -9,32 +9,47 @@ class Flatrack
9
9
  # @private
10
10
  DEFAULT_FORMAT = 'html'
11
11
 
12
- attr_reader :type, :file, :format
12
+ attr_reader :base_path, :type, :file, :format
13
13
  delegate :render, to: :@renderer
14
14
 
15
+ def self.register_path(path)
16
+ classes.each do |klass|
17
+ files = Dir.glob File.join path, '**', "*.#{klass::RENDERS}"
18
+ Tilt.register klass, *files
19
+ end
20
+ end
21
+
15
22
  # Creates a new template instance and invokes find
16
23
  # @param type [Symbol] the type of template
17
24
  # @param format [String] the format e.g. html
18
25
  # @param file [String] the location of the file
19
- def self.find(type, format, file)
20
- new(type, format, file)
26
+ def self.find(base_path, type, format, file)
27
+ new(base_path, type, format, file)
21
28
  end
22
29
 
23
30
  # Creates a new template instance
24
31
  # @param type [Symbol] the type of template
25
32
  # @param format [String] the format e.g. html
26
33
  # @param file [String] the location of the file
27
- def initialize(type, format, file)
34
+ def initialize(base_path, type, format, file)
35
+ @base_path = base_path
28
36
  @format = format || DEFAULT_FORMAT
29
37
  @type, @file = type, file.to_s
30
- @renderer = find
38
+ @renderer = find
31
39
  end
32
40
 
33
41
  private
34
42
 
43
+ def self.classes
44
+ constants.map { |k| const_get k }.select do |klass|
45
+ klass.is_a?(Class) && klass < Tilt::Template
46
+ end
47
+ end
48
+
35
49
  def find
36
50
  template = find_by_type
37
51
  fail FileNotFound, "could not find #{file}" unless template
52
+ template = File.expand_path template
38
53
  Tilt.new template, options
39
54
  rescue RuntimeError
40
55
  raise TemplateNotFound, "could not find a renderer for #{file}"
@@ -48,11 +63,15 @@ class Flatrack
48
63
  end
49
64
 
50
65
  def find_by_type
51
- if File.exist?(file)
66
+ paths = [base_path, Flatrack.gem_root]
67
+
68
+ # To support direct html files
69
+ if paths.any? { |path| file.start_with? path } && File.exist?(file)
52
70
  file
53
71
  else
54
- file_with_format = [file, format].compact.join('.')
55
- Dir[File.join type.to_s.pluralize, "#{file_with_format}*"].first
72
+ file_without_format = File.join(File.dirname(file), File.basename(file, ".#{format}"))
73
+ file_with_format = [file_without_format, format].compact.join('.')
74
+ Dir[File.join base_path, type.to_s.pluralize, "#{file_with_format}*"].first
56
75
  end
57
76
  end
58
77
  end
@@ -2,6 +2,8 @@ class Flatrack
2
2
  class Template
3
3
  # The tilt template for rendering ERB in flatrack
4
4
  class Erubis < Tilt::ErubisTemplate
5
+ RENDERS = 'erb'
6
+
5
7
  extend ActiveSupport::Autoload
6
8
  autoload :Handler
7
9
 
@@ -19,5 +21,3 @@ class Flatrack
19
21
  end
20
22
  end
21
23
  end
22
-
23
- Tilt.prefer Flatrack::Template::Erubis, 'erb'
@@ -2,6 +2,8 @@ class Flatrack
2
2
  class Template
3
3
  # The tilt template for rendering HTML in flatrack
4
4
  class Html < Tilt::PlainTemplate
5
+ RENDERS = 'html'
6
+
5
7
  private
6
8
 
7
9
  def evaluate(scope, locals, &block)
@@ -10,5 +12,3 @@ class Flatrack
10
12
  end
11
13
  end
12
14
  end
13
-
14
- Tilt.prefer Flatrack::Template::Html, 'html'
@@ -4,6 +4,8 @@ class Flatrack
4
4
  class Template
5
5
  # The tilt template for rendering Ruby in flatrack
6
6
  class Rb < Tilt::ErubisTemplate
7
+ RENDERS = 'rb'
8
+
7
9
  private
8
10
 
9
11
  def data
@@ -12,5 +14,3 @@ class Flatrack
12
14
  end
13
15
  end
14
16
  end
15
-
16
- Tilt.prefer Flatrack::Template::Rb, 'rb'
@@ -1,5 +1,5 @@
1
1
  # Version
2
2
  class Flatrack
3
3
  # @private
4
- VERSION = '1.3.3'
4
+ VERSION = '1.4.1'
5
5
  end
@@ -19,7 +19,7 @@ class Flatrack
19
19
  include ERB::Util
20
20
 
21
21
  attr_accessor :output_buffer
22
- delegate :use_layout, to: :@response
22
+ delegate :mount_path, :config, :use_layout, to: :@response
23
23
 
24
24
  # initializes a flatrack view
25
25
  # @param response [Flatrack::Response]
@@ -9,8 +9,7 @@ class Flatrack
9
9
  def capture(*args)
10
10
  value = nil
11
11
  buffer = with_output_buffer { value = yield(*args) }
12
- string = buffer.presence || value
13
- html_escape string if string.is_a?(String)
12
+ buffer.presence || value
14
13
  end
15
14
 
16
15
  # Use an alternate output buffer for the duration of the block.
@@ -32,7 +32,14 @@ class Flatrack
32
32
  # @return [String]
33
33
  def link_to(*args, &block)
34
34
  href, options, block = link_to_options(*args, &block)
35
- html_tag :a, link_to_tag_options(href, options || {}), &block
35
+ if href.start_with?('/') && !href.start_with?('//') && mount_path != '/'
36
+ href = File.join '', mount_path, href
37
+ end
38
+ tag_opts = link_to_tag_options(href, options || {})
39
+ if current_path == tag_opts[:href]
40
+ ((tag_opts[:class] ||= '') << ' active').strip!
41
+ end
42
+ html_tag(:a, tag_opts, false, &block)
36
43
  end
37
44
 
38
45
  private
@@ -6,7 +6,7 @@ class Flatrack
6
6
  # @param file [Symbol, String]
7
7
  # @return [String]
8
8
  def render(file, *args)
9
- Template.find(:partial, nil, file.to_s).render(self, *args)
9
+ Template.find(config.site_root, :partial, nil, file.to_s).render(self, *args)
10
10
  end
11
11
  end
12
12
  end
@@ -8,11 +8,32 @@ class Flatrack
8
8
  @response.request.params
9
9
  end
10
10
 
11
- # Returns the path
11
+ # Returns the path before rewrites
12
12
  # @return [String]
13
- def path
13
+ def current_path
14
14
  @response.request.path
15
15
  end
16
+ alias path current_path
17
+
18
+ # Returns the page being displayed
19
+ # @return [String]
20
+ def current_page
21
+ @response.request.page
22
+ end
23
+ alias page current_page
24
+
25
+ # Returns the IP address for the request
26
+ # @return [String]
27
+ def request_ip
28
+ @response.request.env['REMOTE_ADDR']
29
+ end
30
+
31
+ # Returns the cookies
32
+ # @return [Hash]
33
+ def cookies
34
+ @response.request.env['rack.cookies']
35
+ end
36
+
16
37
  end
17
38
  end
18
39
  end
@@ -7,11 +7,11 @@ class Flatrack
7
7
 
8
8
  # @private
9
9
  PRE_CONTENT_STRINGS = {
10
- textarea: "\n"
10
+ textarea: "\n"
11
11
  }
12
12
 
13
13
  # @private
14
- BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
14
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
15
15
  autoplay controls loop selected hidden scoped
16
16
  async defer reversed ismap seamless muted
17
17
  required autofocus novalidate formnovalidate open
@@ -37,16 +37,17 @@ class Flatrack
37
37
  # @param options [Hash] the html options for the tag
38
38
  # @yield the tag content
39
39
  # @return [String]
40
- def html_tag(name, content_or_options_with_block = nil, options = nil,
41
- escape = true, &block)
40
+ def html_tag(name, *args, &block)
41
+ content, options, escape = args
42
42
  if block_given?
43
- if content_or_options_with_block.is_a?(Hash)
44
- options = content_or_options_with_block
45
- end
46
- html_tag_string(name, capture(&block), options, escape)
43
+ check_arguments [name, *args], 1..3
44
+ options, escape = content, options
45
+ content = capture(&block)
47
46
  else
48
- html_tag_string(name, content_or_options_with_block, options, escape)
47
+ check_arguments [name, *args], 2..4
49
48
  end
49
+ escape = true if escape.nil?
50
+ html_tag_string(name, content, options, escape)
50
51
  end
51
52
 
52
53
  # Returns an HTML image tag
@@ -77,6 +78,13 @@ class Flatrack
77
78
 
78
79
  private
79
80
 
81
+ def check_arguments(args, number_or_range)
82
+ range = number_or_range.is_a?(Fixnum) ? [number_or_range] : number_or_range
83
+ unless range.include? args.size
84
+ raise ArgumentError, "wrong number of arguments (#{args.count} for #{number_or_range.inspect})"
85
+ end
86
+ end
87
+
80
88
  def html_tag_string(name, content, options, escape = true)
81
89
  tag_options = tag_options(options, escape) if options
82
90
  content = h(content) if escape && !content.nil?
@@ -115,8 +123,8 @@ class Flatrack
115
123
  def data_tag_option(key, value, escape)
116
124
  key = "data-#{key.to_s.dasherize}"
117
125
  value = value.to_json unless value.is_a?(String) ||
118
- value.is_a?(Symbol) ||
119
- value.is_a?(BigDecimal)
126
+ value.is_a?(Symbol) ||
127
+ value.is_a?(BigDecimal)
120
128
  tag_option(key, value, escape)
121
129
  end
122
130