landline 0.9.3 → 0.12.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58106097aed53f3fb0edd51bf2d9ecf8ba9d976946ffd7e4570c7f1b5ecdafa7
4
- data.tar.gz: 2b1a03b8a2afeb431a9afe0207a7f17a9ea5439372cccd2c7d2e02b50f544ff1
3
+ metadata.gz: d4924570720bd14c3d6149435782f59a64cd7c36727da5a204462653125de65d
4
+ data.tar.gz: 8f06e6d9194aee22eb39752047c548fda980964548b0f5c78f20200e7f441c6e
5
5
  SHA512:
6
- metadata.gz: 9422f97e4310cea957b3c8ee6aed9ecc279bdffbb3e8578263a1f03316881d2833a3e3bdac42816a077702d3501d7c71027d6e7f5d72a8e1cf34ca4e114f66b8
7
- data.tar.gz: ea8a961e1a6cbb755a8be74c75288932c736174fdef1a7c04c5ef5f6d5d3e0687f393ff5076a8435c1e6eb57978c4993f0152a38af5e5ec77c99adfdedfffe6c
6
+ metadata.gz: 353d30b81860f95e23d542e3b954e3fd1be308fa1cbd534017518a02238d5a79e886cd65e7237380be660286795cfe134c703fb5c2b19765420a065a5400f5d1
7
+ data.tar.gz: d9be7521e662b6ff25f5cf7ac9c98bfe7f6d38a174cf3b9d95110b2c8ff42c500cb0e916a4961dadb48263566aa58812e2b3b5973b0e15c458b69856d0460d25
data/HACKING.md CHANGED
@@ -23,8 +23,3 @@ To keep things beautiful, consider following recommendations:
23
23
  - Document classes as if the next maintainer after you has you at gunpoint.
24
24
  Document thoroughly, use YARD tags and **never** skip on public method
25
25
  docs and class docs. As an example, consider Landline::PatternMatching::Glob.
26
- - Unit tests suck for many reasons. However, if you're writing a class that
27
- does not have any dependents and which is frequently used, consider making
28
- a unit test for it. People that might have to fix things further along
29
- will be very thankful.
30
-
data/README.md CHANGED
@@ -2,25 +2,15 @@
2
2
 
3
3
  Landline is a library that provides a minimalistic DSL for creating
4
4
  web services. It doesn't include patterns, middleware, or anything that
5
- could be considered application logic. It does a few things, and hopefully
6
- it does them well:
5
+ could be considered application logic, besides the basic primitives
6
+ It does a few things, and hopefully it does them well.
7
7
 
8
- - Routing HTTP requests to handlers
9
- - Processing HTTP requests (cookies, headers, etc.)
10
- - Filtering, preprocessing and postprocessing requests
11
- - Creating responses from templates using various template engines
12
- - Parsing and handling forms and queries
13
- - Connecting multiple Landline applications together
14
-
15
- As such, the library is pretty thin and can be used to build more complex
16
- applications.
17
-
18
- As of now it is using Rack as the webserver adapter, but ideally it
19
- shouldn't take much work to make it run on top of any webserver.
20
-
21
- Landline was made mostly for fun. Ideally it will become something more,
8
+ Landline was made mostly for fun. ~~Ideally it will become something more,
22
9
  but as of yet it's just an experiment revolving around Ruby Metaprogramming
23
- and its DSL capabilities.
10
+ and its DSL capabilities.~~ Since then, it has somewhat matured, and while
11
+ it's still not entirely advisable to use in production due to the experimental
12
+ nature of the framework, you're free to test it, see if it works, and if it
13
+ doesn't, supply (hopefully constructive) criticism and/or suggestions.
24
14
 
25
15
  ## Examples
26
16
 
@@ -85,7 +75,7 @@ end
85
75
  run app
86
76
  ```
87
77
 
88
- Static file serving
78
+ Static file serving with nginx-like syntax and file globbing
89
79
  (Note: index applies *only* to /var/www (to the path its defined in))
90
80
 
91
81
  ```ruby
@@ -100,7 +90,7 @@ end
100
90
  run app
101
91
  ```
102
92
 
103
- Logging on a particular path
93
+ Preprocessing requests on a subset of handlers
104
94
 
105
95
  ```ruby
106
96
  require 'landline'
@@ -127,8 +117,72 @@ end
127
117
  run app
128
118
  ```
129
119
 
120
+ Class interface with middleware support
121
+
122
+ ```ruby
123
+ require 'landline'
124
+
125
+ class TimerMiddleware
126
+ def initialize(app)
127
+ @app = app
128
+ end
129
+
130
+ def call(*data)
131
+ puts("Request accepted")
132
+ before = Time.now
133
+ output = @app.call(*data)
134
+ puts("Time elapsed: #{(Time.now - before) * 1000}ms")
135
+ output
136
+ end
137
+ end
138
+
139
+ class Application < Landline::App
140
+ use TimerMiddleware
141
+
142
+ setup do
143
+ get "/hello" do
144
+ "Hello world!"
145
+ end
146
+ end
147
+ end
148
+
149
+ run Application.new
150
+ ```
151
+
130
152
  And a lot more to be found in /examples in this repo.
131
153
 
154
+
155
+ ## Design goals
156
+
157
+ Out of the box, Landline is designed to do the following:
158
+
159
+ - Routing HTTP requests to handlers
160
+ - Processing HTTP requests (cookies, headers, etc.)
161
+ - Filtering, preprocessing, postprocessing requests
162
+ - Deferring block execution until after the request gets processed
163
+ - Creating responses from templates using various template engines
164
+ - Parsing and handling forms and queries
165
+ - Connecting multiple ~~Landline~~ Rack applications together
166
+ - Sending files using nginx-style configuration system
167
+ - A lot of basic Rack things such as plugging in middleware, BEING middleware,
168
+ or sending Rack-compatible environment to another Rack application
169
+
170
+ As such, the library is pretty thin and can be used to build more complex
171
+ applications. This is intentional, and hopefully will remain that way.
172
+
173
+ Additionally, there are a few extra things landline can do, which can be used
174
+ by `require`ing from the `landline/extensions` directory. Please note, however,
175
+ that some of that functionality may require additional dependencies, which
176
+ would otherwise be optional. This functionality includes:
177
+
178
+ - PHP-like Session handling (via `landline/extensions/session`)
179
+ - Websockets (via `landline/extensions/websockets`) (available for testing)
180
+ - (Probably something else eventually)
181
+
182
+ Landline is built entirely on Rack webserver interface, while being agnostic
183
+ to any and all underlying webservers (such as Puma, Thin, Unicorn and such).
184
+ For the foreseeable future, this design decision will not change.
185
+
132
186
  ## Name
133
187
 
134
188
  The name is, quite literally, a metaphor for request routing.
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Landline
4
+ # Rack application interface
5
+ class App
6
+ # TODO: fix this mess somehow (probably impossible)
7
+
8
+ # @!parse include Landline::DSL::PathMethods
9
+ # @!parse include Landline::DSL::PathConstructors
10
+ # @!parse include Landline::DSL::ProbeConstructors
11
+ # @!parse include Landline::DSL::ProbeMethods
12
+ # @!parse include Landline::DSL::CommonMethods
13
+ class << self
14
+ # Duplicate used middleware for the subclassed app
15
+ def inherited(subclass)
16
+ super(subclass)
17
+ subclass.middleware = @middleware.dup
18
+ end
19
+
20
+ # Include a middleware in application
21
+ # @param middleware [Class]
22
+ def use(middleware)
23
+ @middleware ||= []
24
+ @middleware.append(middleware)
25
+ end
26
+
27
+ # Setup block
28
+ # @param block [#call]
29
+ def setup(&block)
30
+ @setup_block = block
31
+ end
32
+
33
+ attr_accessor :middleware, :setup_block
34
+ end
35
+
36
+ def initialize(*args, **opts)
37
+ @app = ::Landline::Server.new(*args, **opts, &self.class.setup_block)
38
+ self.class.middleware&.reverse_each do |cls|
39
+ @app = cls.new(@app)
40
+ end
41
+ end
42
+
43
+ # Rack ingress point.
44
+ # @param env [Hash]
45
+ # @return [Array(Integer,Hash,Array)]
46
+ def call(env)
47
+ @app.call(env)
48
+ end
49
+ end
50
+ end
@@ -5,6 +5,7 @@ module Landline
5
5
  module DSL
6
6
  # Path (and subclasses) DSL constructors
7
7
  module PathConstructors
8
+ # (in Landline::Path context)
8
9
  # Append a Node child object to the list of children
9
10
  def register(obj)
10
11
  unless obj.is_a? Landline::Node
@@ -14,11 +15,13 @@ module Landline
14
15
  @origin.children.append(obj)
15
16
  end
16
17
 
18
+ # (in Landline::Path context)
17
19
  # Create a new {Landline::Path} object
18
20
  def path(path, **args, &setup)
19
21
  register(Landline::Path.new(path, parent: @origin, **args, &setup))
20
22
  end
21
23
 
24
+ # (in Landline::Path context)
22
25
  # Create a new {Landline::Handlers::Probe} object
23
26
  def probe(path, **args, &_setup)
24
27
  register(Landline::Handlers::Probe.new(path,
@@ -26,6 +29,7 @@ module Landline
26
29
  **args))
27
30
  end
28
31
 
32
+ # (in Landline::Path context)
29
33
  # Create a new {Landline::Handlers::GETHandler} object
30
34
  def get(path, **args, &setup)
31
35
  register(Landline::Handlers::GET.new(path,
@@ -34,6 +38,7 @@ module Landline
34
38
  &setup))
35
39
  end
36
40
 
41
+ # (in Landline::Path context)
37
42
  # create a new {Landline::Handlers::POSTHandler} object
38
43
  def post(path, **args, &setup)
39
44
  register(Landline::Handlers::POST.new(path,
@@ -42,6 +47,7 @@ module Landline
42
47
  &setup))
43
48
  end
44
49
 
50
+ # (in Landline::Path context)
45
51
  # Create a new {Landline::Handlers::PUTHandler} object
46
52
  def put(path, **args, &setup)
47
53
  register(Landline::Handlers::PUT.new(path,
@@ -50,6 +56,7 @@ module Landline
50
56
  &setup))
51
57
  end
52
58
 
59
+ # (in Landline::Path context)
53
60
  # Create a new {Landline::Handlers::HEADHandler} object
54
61
  def head(path, **args, &setup)
55
62
  register(Landline::Handlers::HEAD.new(path,
@@ -58,6 +65,7 @@ module Landline
58
65
  &setup))
59
66
  end
60
67
 
68
+ # (in Landline::Path context)
61
69
  # Create a new {Landline::Handlers::DELETEHandler} object
62
70
  def delete(path, **args, &setup)
63
71
  register(Landline::Handlers::DELETE.new(path,
@@ -66,6 +74,7 @@ module Landline
66
74
  &setup))
67
75
  end
68
76
 
77
+ # (in Landline::Path context)
69
78
  # Create a new {Landline::Handlers::CONNECTHandler} object
70
79
  def connect(path, **args, &setup)
71
80
  register(Landline::Handlers::CONNECT.new(path,
@@ -74,6 +83,7 @@ module Landline
74
83
  &setup))
75
84
  end
76
85
 
86
+ # (in Landline::Path context)
77
87
  # Create a new {Landline::Handlers::TRACEHandler} object
78
88
  def trace(path, **args, &setup)
79
89
  register(Landline::Handlers::TRACE.new(path,
@@ -82,6 +92,7 @@ module Landline
82
92
  &setup))
83
93
  end
84
94
 
95
+ # (in Landline::Path context)
85
96
  # Create a new {Landline::Handlers::PATCHHandler} object
86
97
  def patch(path, **args, &setup)
87
98
  register(Landline::Handlers::PATCH.new(path,
@@ -90,6 +101,7 @@ module Landline
90
101
  &setup))
91
102
  end
92
103
 
104
+ # (in Landline::Path context)
93
105
  # Create a new {Landline::Handlers::OPTIONSHandler} object
94
106
  def options(path, **args, &setup)
95
107
  register(Landline::Handlers::OPTIONS.new(path,
@@ -98,10 +110,19 @@ module Landline
98
110
  &setup))
99
111
  end
100
112
 
113
+ # (in Landline::Path context)
101
114
  # Create a new {Landline::Handlers::GETHandler} that serves static files
102
115
  def serve(path)
103
116
  register(Landline::Handlers::Serve.new(path, parent: @origin))
104
117
  end
118
+
119
+ # (in Landline::Path context)
120
+ # Create a new application crosscall link (acts like #call in probe context and strips its path from request)
121
+ def link(path, application)
122
+ register(Landline::Handlers::Link.new(path,
123
+ application,
124
+ parent: @origin))
125
+ end
105
126
  end
106
127
  end
107
128
  end
@@ -4,8 +4,9 @@ module Landline
4
4
  module DSL
5
5
  # Probe (and subclasses) DSL construct
6
6
  module ProbeConstructors
7
+ # (in Landline::Probe context)
7
8
  # Create a new erb template
8
- # @see {Landline::Template#new}
9
+ # @see Landline::Template#new
9
10
  def erb(input, vars = {})
10
11
  Landline::Templates::ERB.new(input,
11
12
  vars,
@@ -13,8 +14,9 @@ module Landline
13
14
  filename: caller_locations[0].path)
14
15
  end
15
16
 
17
+ # (in Landline::Probe context)
16
18
  # Create a new erb template using Erubi engine
17
- # @see {Landline::Template#new}
19
+ # @see Landline::Template#new
18
20
  # @param freeze [Boolean] whether to use frozen string literal
19
21
  # @param capture [Boolean] whether to enable output capturing
20
22
  def erubi(input, vars = {}, freeze: true, capture: false)
@@ -4,6 +4,7 @@ module Landline
4
4
  module DSL
5
5
  # Methods shared by probes, preprocessors and filters.
6
6
  module CommonMethods
7
+ # (in Landline::Probe context)
7
8
  # Stop execution and generate a boilerplate response with the given code
8
9
  # @param errorcode [Integer]
9
10
  # @param backtrace [Array(String), nil]
@@ -18,6 +19,7 @@ module Landline
18
19
  )
19
20
  end
20
21
 
22
+ # (in Landline::Probe context)
21
23
  # Bounce request to the next handler
22
24
  # @raise [UncaughtThrowError] throws :break to get out of the callback
23
25
  def bounce
@@ -5,6 +5,37 @@ module Landline
5
5
  module DSL
6
6
  # Common path methods
7
7
  module PathMethods
8
+ # (in Landline::Path context)
9
+ # Bounce request if no handler found instead of issuing 404
10
+ def bounce
11
+ @origin.bounce = true
12
+ end
13
+
14
+ # (in Landline::Path context)
15
+ # Unset bounce
16
+ def nobounce
17
+ @origin.bounce = false
18
+ end
19
+
20
+ # (in Landline::Path context)
21
+ # Create a status code handler on path.
22
+ # Recursively applies to all paths unless overridden.
23
+ # @param code [Integer, nil] Specify a status code to handle
24
+ # @param block [#call] Block to run on given code
25
+ def handle(code = nil, &block)
26
+ @origin.properties["handle.#{code || 'default'}"] = block
27
+ end
28
+
29
+ # (in Landline::Path context)
30
+ # Insert a pass-through pipeline into request processing
31
+ # (i.e. for error handling purposes).
32
+ # Passed block should yield request (and return yielded data back).
33
+ # @param block [#call] block that yields request
34
+ def pipeline(&block)
35
+ @origin.pipeline = block
36
+ end
37
+
38
+ # (in Landline::Path context)
8
39
  # Set path index
9
40
  # @param index [Array,String]
10
41
  def index(index)
@@ -18,18 +49,21 @@ module Landline
18
49
  end
19
50
  end
20
51
 
52
+ # (in Landline::Path context)
21
53
  # Set root path (appends matched part of the path).
22
54
  # @param path [String]
23
55
  def root(path)
24
- @origin.root = path
56
+ @origin.root = File.expand_path(path)
25
57
  end
26
58
 
59
+ # (in Landline::Path context)
27
60
  # Set root path (without appending matched part).
28
61
  # @param path [String]
29
62
  def remap(path)
30
- @origin.remap = path
63
+ @origin.remap = File.expand_path(path)
31
64
  end
32
65
 
66
+ # (in Landline::Path context)
33
67
  # Add a preprocessor to the path.
34
68
  # Does not modify path execution.
35
69
  # @param block [#call]
@@ -39,6 +73,7 @@ module Landline
39
73
  block
40
74
  end
41
75
 
76
+ # (in Landline::Path context)
42
77
  # Add a postprocessor to the path.
43
78
  # @param block [#call]
44
79
  # @yieldparam request [Landline::Request]
@@ -48,6 +83,10 @@ module Landline
48
83
  block
49
84
  end
50
85
 
86
+ alias before preprocess
87
+ alias after postprocess
88
+
89
+ # (in Landline::Path context)
51
90
  # Add a filter to the path.
52
91
  # Blocks path access if a filter returns false.
53
92
  # @param block [#call]
@@ -57,10 +96,12 @@ module Landline
57
96
  block
58
97
  end
59
98
 
99
+ # (in Landline::Path context)
60
100
  # Include an application as a child of path.
101
+ # @deprecated this method is being deprecated due to strong dependency on the framework
61
102
  # @param filename [String]
62
103
  def plugin(filename)
63
- self.define_singleton_method(:run) do |object|
104
+ define_singleton_method(:run) do |object|
64
105
  unless object.is_a? Landline::Node
65
106
  raise ArgumentError, "not a node instance or subclass instance"
66
107
  end
@@ -68,9 +109,9 @@ module Landline
68
109
  object
69
110
  end
70
111
  @origin.children.append(
71
- self.instance_eval(File.read(filename), filename)
112
+ instance_eval(File.read(filename), filename)
72
113
  )
73
- self.singleton_class.undef_method :run
114
+ singleton_class.undef_method :run
74
115
  end
75
116
  end
76
117
  end
@@ -4,17 +4,20 @@ require_relative '../response'
4
4
  require_relative '../util/multipart'
5
5
  require_relative '../util/parseutils'
6
6
  require_relative '../util/html'
7
+ require 'json'
7
8
 
8
9
  module Landline
9
10
  module DSL
10
11
  # Common methods for Probe objects
11
12
  module ProbeMethods
13
+ # (in Landline::Probe context)
12
14
  # Get the current request
13
15
  # @return [Landline::Request]
14
16
  def request
15
17
  @origin.request
16
18
  end
17
19
 
20
+ # (in Landline::Probe context)
18
21
  # Set response status (generate response if one doesn't exist yet)
19
22
  # @param status [Integer] http status code
20
23
  def status(status)
@@ -22,8 +25,59 @@ module Landline
22
25
  @origin.response.status = status
23
26
  end
24
27
 
28
+ # (in Landline::Probe context)
29
+ # Add a finalizer callable to the response
30
+ # @param callable [#call]
31
+ def defer(&callable)
32
+ rack = @origin.request.rack
33
+ if rack.respond_to?(:response_finished)
34
+ rack.response_finished.append(callable)
35
+ end
36
+ # puma for some reason isn't compatible with the 3.0.0 spec on this
37
+ rack.after_reply.append(callable) if rack.respond_to?(:after_reply)
38
+ end
39
+
40
+ # (in Landline::Probe context)
41
+ # Do serverside request redirection
42
+ # @note this essentially reprocesses the whole request - be mindful of processing time!
43
+ # @param path [String]
44
+ def jump(path)
45
+ @origin.request.path = path
46
+ throw(:break, [307, { "x-internal-jump": true }, []])
47
+ end
48
+
49
+ # (in Landline::Probe context)
50
+ # Do clientside request redirection via 302 code
51
+ # @param path [String]
52
+ def redirect(path)
53
+ throw(:break, [302, { "location": path }, []])
54
+ end
55
+
56
+ # (in Landline::Probe context)
57
+ # Do clientside request redirection via 307 code
58
+ # @param path [String]
59
+ def redirect_with_method(path)
60
+ throw(:break, [307, { "location": path }, []])
61
+ end
62
+
25
63
  alias code status
26
64
 
65
+ # (in Landline::Probe context)
66
+ # Set a partial hijack callback
67
+ # @param block [#call] Callable block
68
+ def partial_hijack(&block)
69
+ @origin.response ||= Landline::Response.new
70
+ @origin.response.add_header("rack.hijack", block)
71
+ end
72
+
73
+ # (in Landline::Probe context)
74
+ # Fully hijack IO
75
+ # @return [IO]
76
+ def hijack
77
+ @origin.request.hijack.call
78
+ end
79
+
80
+ # (in Landline::Probe context)
27
81
  # Set response header (generate response if one doesn't exist yet)
28
82
  # @param key [String] header name
29
83
  # @param value [String] header value
@@ -39,10 +93,11 @@ module Landline
39
93
  end
40
94
 
41
95
  @origin.response = (@origin.response or Landline::Response.new)
42
- key = key.downcase
96
+ key = key.downcase.to_s
43
97
  @origin.response.add_header(key, value)
44
98
  end
45
99
 
100
+ # (in Landline::Probe context)
46
101
  # Delete a header value from the headers hash
47
102
  # If no value is provided, deletes all key entries
48
103
  # @param key [String] header name
@@ -60,9 +115,10 @@ module Landline
60
115
  raise ArgumentError, "value key has invalid characters"
61
116
  end
62
117
 
63
- @origin.response.delete_header(key, value)
118
+ @origin.response.delete_header(key.to_s, value)
64
119
  end
65
120
 
121
+ # (in Landline::Probe context)
66
122
  # Set response cookie
67
123
  # @see Landline::Cookie.new
68
124
  def cookie(*params, **options)
@@ -72,6 +128,7 @@ module Landline
72
128
  )
73
129
  end
74
130
 
131
+ # (in Landline::Probe context)
75
132
  # Delete a cookie
76
133
  # If no value is provided, deletes all cookies with the same key
77
134
  # @param key [String] cookie key
@@ -82,21 +139,17 @@ module Landline
82
139
  @origin.response.delete_cookie(key, value)
83
140
  end
84
141
 
142
+ # (in Landline::Probe context)
85
143
  # Checks if current request has multipart/form-data associated with it
86
144
  # @return [Boolean]
87
145
  def form?
88
- value, opts = Landline::Util::ParserCommon.parse_value(
89
- request.headers["content-type"]
90
- )
91
- if value == "multipart/form-data" and
92
- opts["boundary"]
93
- true
94
- else
95
- false
96
- end
146
+ value, opts = _verify_content_type('multipart/form-data')
147
+ !!(value && opts && opts['boundary'])
97
148
  end
98
149
 
150
+ # (in Landline::Probe context)
99
151
  # Returns formdata
152
+ # @note reads request.input - may nullify request.body.
100
153
  # @return [Hash{String=>(String,Landline::Util::FormPart)}]
101
154
  def form
102
155
  _, opts = Landline::Util::ParserCommon.parse_value(
@@ -107,23 +160,88 @@ module Landline
107
160
  ).to_h
108
161
  end
109
162
 
163
+ # (in Landline::Probe context)
164
+ # Checks if current request has urlencoded query string
165
+ # @return [Boolean]
166
+ def query?
167
+ !!_verify_content_type("application/x-www-form-urlencode")
168
+ end
169
+
170
+ # (in Landline::Probe context)
171
+ # Returns parsed query hash
172
+ # @note reads request.body - may nullify .input, .body data is memoized
173
+ # @return [Hash{String => Object}] query data
174
+ def query
175
+ Landline::Util::Query.new(request.body).parse
176
+ end
177
+
178
+ # (in Landline::Probe context)
179
+ # Returns shallow parsed query hash
180
+ # @note reads request.body - may nullify .input, .body data is memoized
181
+ # @return [Hash{String => Object}] query data
182
+ def query_shallow
183
+ Landline::Util::Query.new(request.body).parse_shallow
184
+ end
185
+
186
+ # (in Landline::Probe context)
187
+ # Check if body is a JSON object
188
+ # @return [Boolean]
189
+ def json?
190
+ !!_verify_content_type('application/json')
191
+ end
192
+
193
+ # (in Landline::Probe context)
194
+ # Return parse JSON object
195
+ # @note reads request.input - may nullify request.body.
196
+ # @return [Object]
197
+ def json
198
+ JSON.parse(request.input)
199
+ end
200
+
201
+ # (in Landline::Probe context)
110
202
  # Open a file relative to current filepath
111
203
  # @see File.open
112
204
  def file(path, mode = "r", *all, &block)
113
205
  File.open("#{request.filepath}/#{path}", mode, *all, &block)
114
206
  end
115
207
 
208
+ # (in Landline::Probe context)
116
209
  # Escape HTML entities
117
210
  # @see Landline::Util.escape_html
118
211
  def escape_html(text)
119
212
  Landline::Util.escape_html(text)
120
213
  end
121
214
 
215
+ # (in Landline::Probe context)
122
216
  # Unescape HTML entities
123
217
  # @see Landline::Util.escape_html
124
218
  def unescape_html(text)
125
219
  Landline::Util.unescape_html(text)
126
220
  end
221
+
222
+ # (in Landline::Path context)
223
+ # Pass the requested environment to a different application
224
+ # @param application [#call] Rack application
225
+ # @return [Array(Integer, Hash{String => Object}, Object)] response
226
+ def call(application)
227
+ application.call(@origin.request.env)
228
+ end
229
+
230
+ private
231
+
232
+ def _verify_content_type(type)
233
+ return false unless request.headers['content-type']
234
+
235
+ value, opts = Landline::Util::ParserCommon.parse_value(
236
+ request.headers["content-type"]
237
+ )
238
+ if value == type and
239
+ request.input
240
+ [value, opts]
241
+ else
242
+ false
243
+ end
244
+ end
127
245
  end
128
246
  end
129
247
  end
@@ -7,9 +7,19 @@ module Landline
7
7
  module DSL
8
8
  # Common methods for template contexts
9
9
  module TemplateMethods
10
+ # (in Landline::Template context)
10
11
  # Import a template part
12
+ # @param filepath [String, File] path to the file (or the file itself)
13
+ # @return [String] compiled template
11
14
  def import(filepath)
12
- @parent_template.import(file(filepath)).run
15
+ template = if filepath.is_a? File
16
+ filepath
17
+ elsif filepath.start_with? "/"
18
+ File.open(filepath)
19
+ else
20
+ file(filepath)
21
+ end
22
+ @parent_template.import(template).run
13
23
  end
14
24
  end
15
25
  end