simple-httpd 0.3.4 → 0.3.5

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: e552a1dc3cc22d3fa1e614a440e86820ec7f95157711f77cfb5b2492966a4414
4
- data.tar.gz: d014f9712b6493403d09a35b650467070dd46079a6bf401f22aa2da9edcb79a3
3
+ metadata.gz: 00457b4ed11c8a501e43a4c4826ef6d78722b072ffff0bab1b0c609c797e14f7
4
+ data.tar.gz: ed35d788fba032b31b971f29e07b23cf490ffc1d96a3aff9369bc812bda22dde
5
5
  SHA512:
6
- metadata.gz: 6c258058969660cf9c45a6a1fb5193b1f5fdba24cda123bd77257531251da295082c5c71af48af16aa01fae9f28539c66409b8900d005ba525ad4ab52aa70ad8
7
- data.tar.gz: 5bf9584a2c7be956483792568aa19e8996ec116ae8c49998da39e104c5943414ed3b6fb8ef6d3664958c851037292ef769f6b4248b7cca894a21d43c03d1aa11
6
+ metadata.gz: 0d57c201cad87a16655eb6e05a4b527176603ab063d08878b44711741babd3fb62140224b5e7cfd0c6ff3e2937c5d177c6ffcb4d88143903f99d36bd5d937f02
7
+ data.tar.gz: a55d03f273b5a634262a55916c15690bf845641f69af2217a82d4a778b84af089cdb3722df89c25d4d1d847a2654f4c858c141900115e895c8fa3d8ef55dbc4b
data/.envrc ADDED
@@ -0,0 +1,7 @@
1
+ # A direnv config file: https://github.com/direnv/direnv
2
+
3
+ if [ "$(type -t direnv_load)" = 'function' ]; then
4
+ # Whatever you want only direnv to execute
5
+ PATH_add bin
6
+ fi
7
+
data/.rubocop.yml CHANGED
@@ -16,6 +16,9 @@ Metrics/LineLength:
16
16
  Metrics/MethodLength:
17
17
  Max: 20
18
18
 
19
+ Metrics/AbcSize:
20
+ Max: 20
21
+
19
22
  Style/SpecialGlobalVars:
20
23
  Enabled: false
21
24
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.4
1
+ 0.3.5
data/examples/ex1/root.rb CHANGED
@@ -1,3 +1,11 @@
1
+ # This would be an example of sleeping for 1 sec with thin/eventmachine.
2
+ #
3
+ # aget "/" do
4
+ # EM.add_timer(1) {
5
+ # body { "hello sync" }
6
+ # }
7
+ # end
8
+
1
9
  get "/" do
2
10
  "root"
3
11
  end
@@ -7,8 +7,6 @@ mount_service ExplicitService do |service|
7
7
  post "/echo/:a" => :explicit_echo
8
8
 
9
9
  put "/echo_context" do
10
- ::Simple::Service.with_context(context) do
11
- ::Simple::Service.invoke(service, :echo_context)
12
- end
10
+ service.invoke :echo_context
13
11
  end
14
12
  end
data/lib/simple/httpd.rb CHANGED
@@ -3,17 +3,6 @@
3
3
  module Simple
4
4
  end
5
5
 
6
- class Simple::Httpd
7
- end
8
-
9
- require "simple/service"
10
- require "simple/httpd/helpers"
11
- require "simple/httpd/base_controller"
12
- require "simple/httpd/version"
13
- require "simple/httpd/mount"
14
- require "simple/httpd/server"
15
- require "simple/httpd/service_adapter"
16
-
17
6
  class Simple::Httpd
18
7
  SELF = self
19
8
 
@@ -39,7 +28,18 @@ class Simple::Httpd
39
28
  def self.logger=(logger)
40
29
  @logger = logger
41
30
  end
31
+ end
42
32
 
33
+ require "simple/service"
34
+ require "simple/httpd/helpers"
35
+ require "simple/httpd/reloader"
36
+ require "simple/httpd/base_controller"
37
+ require "simple/httpd/version"
38
+ require "simple/httpd/mount"
39
+ require "simple/httpd/server"
40
+ require "simple/httpd/service_integration"
41
+
42
+ class Simple::Httpd
43
43
  # Converts the passed in args into a Simple::Httpd application.
44
44
  #
45
45
  # The passed in arguments are used to create a Simple::Httpd object.
@@ -2,18 +2,17 @@
2
2
  # config/routes.rb, **after** this file is loaded. See the end of this file.
3
3
 
4
4
  require "sinatra/base"
5
+ ::Sinatra::Request.include(::Simple::Httpd::Helpers::RequestHeader)
5
6
 
6
7
  class Simple::Httpd::BaseController < Sinatra::Base
7
8
  set :logging, true
8
9
 
9
- # --- Sinatra::Reloader -----------------------------------------------------
10
+ extend Simple::Httpd::Reloader
10
11
 
11
- # Note that Sinatra::Reloader is less thorough than, say, shotgun or the
12
- # Rails development mode, but on the other hand it is much faster, and
13
- # probably useful 90% of the time.
14
- configure :development do
15
- # require "sinatra/reloader"
16
- # register Sinatra::Reloader
12
+ def dispatch!
13
+ self.class.reload! if ::Simple::Httpd.env == "development"
14
+
15
+ super
17
16
  end
18
17
  end
19
18
 
@@ -1,21 +1,22 @@
1
1
  class Simple::Httpd::BaseController
2
- CORS_HEADERS = {
3
- "access-control-allow-credentials" => "true",
4
- "access-control-allow-headers" => "Origin,X-Requested-With,Content-Type,Accept,Session-Id",
5
- "access-control-allow-methods" => "*",
6
- "access-control-allow-origin" => "*",
7
- # "access-control-expose-headers" => "X-Total-Entries,X-Total-Pages,X-Page,X-Per-Page",
8
- # "access-control-max-age" => "-1",
9
- "access-control-max-age" => "600",
10
- "access-control-request-headers" => "Content-Type",
11
- "access-control-request-method" => "GET,POST,PATCH,PUT,DELETE,OPTIONS"
12
- }
2
+ # see https://fetch.spec.whatwg.org/#http-responses
3
+ # see https://stackoverflow.com/questions/24264574/cors-headers-present-only-on-preflight-or-every-request
13
4
 
14
5
  options "*" do
6
+ # The Access-Control max age setting is cached for up to 1 day. This value
7
+ # is capped at different values depending on the browser.
8
+ headers "Access-Control-Max-Age" => "86400"
9
+ headers "Access-Control-Allow-Methods" => "*"
10
+ headers "Access-Control-Allow-Headers" => "Origin,X-Requested-With,Content-Type,Accept,Session-Id"
11
+ headers "Access-Control-Expose-Headers" => "X-Total-Entries,X-Total-Pages,X-Page,X-Per-Page"
12
+
15
13
  200
16
14
  end
17
15
 
18
16
  after do
19
- headers CORS_HEADERS
17
+ # This set of CORS headers must be set on each request.
18
+ headers "Access-Control-Allow-Credentials" => "true",
19
+ "Access-Control-Allow-Origin" => origin,
20
+ "Vary" => "Accept-Encoding, Origin"
20
21
  end
21
22
  end
@@ -1,5 +1,20 @@
1
+ # rubocop:disable Metrics/ClassLength, Lint/Void
2
+ # rubocop:disable Metrics/AbcSize
3
+
1
4
  require_relative "./json"
2
5
 
6
+ # reimplement Sinatra's NotFound handler.
7
+ #
8
+ # The original renders HTML; this is not really useful for us.
9
+ Sinatra::Base
10
+ class Sinatra::Base
11
+ error ::Sinatra::NotFound do
12
+ content_type "text/plain"
13
+
14
+ "Don't know how to handle: #{request.request_method} '#{request.path_info}'"
15
+ end
16
+ end
17
+
3
18
  class Simple::Httpd::BaseController
4
19
  H = ::Simple::Httpd::Helpers
5
20
 
@@ -33,10 +48,25 @@ class Simple::Httpd::BaseController
33
48
  options["description"] ||= options["title"]
34
49
  options["@type"] = error_type(exc)
35
50
  options["@now"] = Time.now.to_f
51
+ options["@request"] = "#{request.request_method} #{request.path}"
52
+
53
+ if Simple::Httpd.env == "development" || Simple::Httpd.env == "test"
54
+ options["@headers"] = request_headers_for_debugging
55
+ options["@backtrace"] = exc.backtrace[0, 10]
56
+ end
36
57
 
37
58
  json options
38
59
  end
39
60
 
61
+ def request_headers_for_debugging
62
+ request.headers.each_with_object({}) do |(key, value), hsh|
63
+ next if /^(Host|Version|Connection|User-Agent|Accept-Encoding)$/ =~ key
64
+ next if key == "Accept" && value == "*/*"
65
+
66
+ hsh[key] = value
67
+ end
68
+ end
69
+
40
70
  if defined?(Expectation)
41
71
 
42
72
  error(Expectation::Matcher::Mismatch) do |exc|
@@ -57,8 +87,6 @@ class Simple::Httpd::BaseController
57
87
  # end
58
88
 
59
89
  error(ArgumentError) do |exc|
60
- STDERR.puts "Caught ArgumentError: #{exc}, from\n\t#{exc.backtrace[0, 5].join("\n\t")}"
61
-
62
90
  render_error exc, status: 422,
63
91
  title: "Invalid input #{exc.inspect}",
64
92
  description: error_description(exc)
@@ -75,16 +103,16 @@ class Simple::Httpd::BaseController
75
103
  class NotAuthorizedError < RuntimeError
76
104
  end
77
105
 
106
+ def not_authorized!(msg)
107
+ raise NotAuthorizedError, msg
108
+ end
109
+
78
110
  error(NotAuthorizedError) do
79
111
  render_error e, status: 403,
80
112
  title: "Not authorized",
81
113
  description: "You don't have necessary powers to access this page."
82
114
  end
83
115
 
84
- def not_authorized!(msg)
85
- raise NotAuthorizedError, msg
86
- end
87
-
88
116
  # -- login required.---------------------------------------------------------
89
117
 
90
118
  class LoginRequiredError < RuntimeError
@@ -123,7 +151,7 @@ class Simple::Httpd::BaseController
123
151
 
124
152
  # -- print unspecified errors.
125
153
 
126
- if ENV["RACK_ENV"] == "production"
154
+ if ::Simple::Httpd.env == "development"
127
155
  error do |exc|
128
156
  content_type :text
129
157
  status 500
@@ -0,0 +1,8 @@
1
+ class Simple::Httpd::BaseController
2
+ helpers do
3
+ def origin
4
+ request["Origin"] ||
5
+ "#{request.scheme}://#{request.host_with_port}"
6
+ end
7
+ end
8
+ end
@@ -1,19 +1,19 @@
1
1
  class ::Simple::Httpd::BaseController
2
- private
3
-
4
- # encodes the result, according to its payload.
5
- #
6
- # This function is used by the service integration code, but
7
- # is potentially useful outside.
8
- def encode_result(result)
9
- case result
10
- when Array, Hash
11
- json(result)
12
- when String
13
- content_type :text
14
- result
15
- else
16
- result
2
+ helpers do
3
+ # encodes the result, according to its payload.
4
+ #
5
+ # This function is used by the service integration code, but
6
+ # is potentially useful outside.
7
+ def encode_result(result)
8
+ case result
9
+ when Array, Hash
10
+ json(result)
11
+ when String
12
+ content_type :text
13
+ result
14
+ else
15
+ result
16
+ end
17
17
  end
18
18
  end
19
19
  end
@@ -55,6 +55,7 @@ module Simple::Httpd::CLI
55
55
  port: port)
56
56
  end
57
57
 
58
+ # rubocop:disable Metrics/AbcSize
58
59
  def routes(*mounts, environment: "development", services: nil)
59
60
  prepare_environment!(environment: environment)
60
61
  app = build_app!(mounts: mounts, services: services)
@@ -65,11 +66,11 @@ module Simple::Httpd::CLI
65
66
  max_verb_len = routes.map(&:verb).map(&:length).max
66
67
  max_path_len = routes.map(&:path).map(&:length).max
67
68
 
68
- routes.
69
- sort_by { |route| [route.path, route.verb] }.
70
- each { |route|
69
+ routes
70
+ .sort_by { |route| [route.path, route.verb] }
71
+ .each do |route|
71
72
  puts format("%#{max_verb_len}s %-#{max_path_len}s %s", route.verb, route.path, route.source_location_str)
72
- }
73
+ end
73
74
  end
74
75
 
75
76
  private
@@ -113,12 +114,6 @@ module Simple::Httpd::CLI
113
114
  end
114
115
  end
115
116
 
116
- def stderr_logger
117
- logger = ::Logger.new STDERR
118
- logger.level = ::Logger::INFO
119
- logger
120
- end
121
-
122
117
  def start_simplecov
123
118
  require "simplecov"
124
119
 
@@ -1,4 +1,15 @@
1
1
  module Simple::Httpd::Helpers
2
+ module RequestHeader
3
+ def headers
4
+ env.each_with_object({}) do |(key, value), hsh|
5
+ next unless key =~ /\AHTTP_(.*)/
6
+
7
+ key = $1.split("_").collect(&:capitalize).join("-")
8
+ hsh[key] = value
9
+ end
10
+ end
11
+ end
12
+
2
13
  extend self
3
14
 
4
15
  private
@@ -16,6 +27,10 @@ module Simple::Httpd::Helpers
16
27
  def shorten_path(path)
17
28
  path = File.absolute_path(path)
18
29
 
30
+ shorten_absolute_path(path)
31
+ end
32
+
33
+ def shorten_absolute_path(path)
19
34
  if path.start_with?(pwd)
20
35
  path = path[pwd.length..-1]
21
36
  path = File.join("./", path) if path =~ /\//
@@ -52,8 +67,11 @@ module Simple::Httpd::Helpers
52
67
  raise "Missing description" unless description
53
68
 
54
69
  subclass = Class.new(klass)
70
+ subclass.define_singleton_method(:description) { description }
55
71
  subclass.define_method(:inspect) { description } if description
56
- instance_eval_paths subclass, paths: paths if paths
72
+
73
+ ::Simple::Httpd::Reloader.attach(subclass, paths: Array(paths))
74
+
57
75
  subclass
58
76
  end
59
77
 
@@ -9,13 +9,17 @@ class Simple::Httpd::Rack::DynamicMount
9
9
 
10
10
  extend Forwardable
11
11
 
12
- delegate :call => :@rack_app # rubocop:disable Style/HashSyntax
13
-
14
12
  def self.build(mount_point, path)
15
13
  expect! path => String
16
14
  new(mount_point, path)
17
15
  end
18
16
 
17
+ def call(env)
18
+ reload! if ::Simple::Httpd.env == "development"
19
+
20
+ @rack_app.call(env)
21
+ end
22
+
19
23
  attr_reader :path
20
24
  attr_reader :mount_point
21
25
 
@@ -24,7 +28,8 @@ class Simple::Httpd::Rack::DynamicMount
24
28
  @path = path.gsub(/\/\z/, "") # remove trailing "/"
25
29
 
26
30
  setup_paths!
27
- load_service_files!
31
+ ::Simple::Httpd::Reloader.attach self, paths: service_files, reloading_instance: nil
32
+
28
33
  @root_controller = build_root_controller # also loads helpers
29
34
  @url_map = build_url_map
30
35
 
@@ -47,25 +52,26 @@ class Simple::Httpd::Rack::DynamicMount
47
52
  logger.info "#{path}: found #{@source_paths.count} sources, #{@helper_paths.count} helpers"
48
53
  end
49
54
 
50
- def load_service_files!
51
- return if path == "." # i.e. mounting current directory
55
+ def service_files
56
+ @service_files ||= _service_files
57
+ end
58
+
59
+ def _service_files
60
+ return [] if path == "." # i.e. mounting current directory
52
61
 
53
62
  service_path = "#{path}.services"
54
- service_files = Dir.glob("#{service_path}/**/*.rb")
55
- return if service_files.empty?
63
+ return [] unless Dir.exist?(service_path)
56
64
 
65
+ service_files = Dir.glob("#{service_path}/**/*.rb").sort
57
66
  logger.info "#{service_path}: loading #{service_files.count} service file(s)"
58
- service_files.sort.each do |path|
59
- logger.debug "Loading service file #{path.inspect}"
60
- load path
61
- end
67
+ service_files
62
68
  end
63
69
 
64
70
  # wraps all helpers into a Simple::Httpd::BaseController subclass
65
71
  def build_root_controller
66
72
  H.subclass ::Simple::Httpd::BaseController,
67
73
  paths: @helper_paths.sort,
68
- description: "root controller at #{path} w/#{@helper_paths.count} helpers"
74
+ description: "<root controller: #{H.shorten_path path}>"
69
75
  end
70
76
 
71
77
  def build_url_map
@@ -73,7 +79,9 @@ class Simple::Httpd::Rack::DynamicMount
73
79
  relative_path = absolute_path[(path.length)..-1]
74
80
 
75
81
  relative_mount_point = relative_path == "/root.rb" ? "/" : relative_path.gsub(/\.rb$/, "")
76
- controller_class = H.subclass @root_controller, description: "controller at #{absolute_path}", paths: absolute_path
82
+ controller_class = H.subclass @root_controller,
83
+ paths: absolute_path,
84
+ description: "<controller:#{H.shorten_absolute_path(absolute_path)}>"
77
85
 
78
86
  controller_class.route_descriptions.each do |route|
79
87
  route = route.prefix(@mount_point, relative_mount_point)
@@ -0,0 +1,61 @@
1
+ module Simple::Httpd::Reloader
2
+ def self.attach(target, paths:, reloading_instance: target)
3
+ target.extend self
4
+ target.load!(paths: paths, reloading_instance: reloading_instance)
5
+ target
6
+ end
7
+
8
+ H = ::Simple::Httpd::Helpers
9
+
10
+ attr_accessor :reloading_paths
11
+
12
+ def load!(paths:, reloading_instance:)
13
+ paths = Array(paths)
14
+ paths = nil if paths.empty?
15
+
16
+ @__reload_paths__ = paths
17
+ @__reloading_instance__ = reloading_instance
18
+
19
+ reload_all_changed_files
20
+ end
21
+
22
+ def reload!
23
+ # if this is a class, and its superclass is also reloadable,
24
+ # reload the superclass first.
25
+ if respond_to?(:superclass) && superclass&.respond_to?(:reload!)
26
+ superclass.reload!
27
+ end
28
+
29
+ reload_all_changed_files
30
+ end
31
+
32
+ private
33
+
34
+ def reload_all_changed_files
35
+ return unless @__reload_paths__
36
+
37
+ @__reload_paths__.each do |path|
38
+ reload_file_if_necessary(path)
39
+ end
40
+ end
41
+
42
+ def reload_file_if_necessary(path)
43
+ @__source_mtimes_by_path__ ||= {}
44
+
45
+ mtime = File.mtime(path)
46
+ return if @__source_mtimes_by_path__[path] == mtime
47
+
48
+ Simple::Httpd.logger.debug do
49
+ verb = @__source_mtimes_by_path__.key?(path) ? "reloading" : "loading"
50
+ "#{verb} #{H.shorten_path path}"
51
+ end
52
+
53
+ if @__reloading_instance__
54
+ @__reloading_instance__.instance_eval File.read(path), path, 1
55
+ else
56
+ load path
57
+ end
58
+
59
+ @__source_mtimes_by_path__[path] = mtime
60
+ end
61
+ end
@@ -18,19 +18,29 @@ class Simple::Httpd
18
18
 
19
19
  ::Simple::Httpd.logger.info "Starting httpd server on http://#{host}:#{port}/"
20
20
 
21
+ app = ::Rack::CommonLogger.new(app)
21
22
  app = ::Rack::Lint.new(app) if environment != "production"
22
23
 
23
24
  # re/AccessLog: the AccessLog setting points WEBrick's access logging to the
24
25
  # NullLogger object.
25
26
  #
26
- # Instead we'll use a combination of Rack::CommonLogger (see Simple::Httpd.app),
27
- # and sinatra's logger (see Simple::Httpd::BaseController).
28
- ::Rack::Server.start app: app,
29
- Host: host,
30
- Port: port,
31
- environment: environment,
32
- Logger: build_logger,
33
- AccessLog: [[NullLogger, ""]]
27
+ # We do not set the environment. Rack is using this to load different
28
+ # default middlewares (ShowException, Lint, CommonLogger) depending on
29
+ # the environment setting (which should be either "development" or
30
+ # "deployment").
31
+ server_opts = {
32
+ app: app,
33
+ Host: host,
34
+ Port: port,
35
+ Logger: build_logger,
36
+ AccessLog: [[NullLogger, ""]]
37
+ }
38
+
39
+ unless ::Simple::Httpd.env == "development"
40
+ server_opts.update workers: 4, min_threads: 4
41
+ end
42
+
43
+ ::Rack::Server.start server_opts
34
44
  end
35
45
 
36
46
  private
@@ -1,19 +1,29 @@
1
1
  require "simple-service"
2
2
 
3
- module Simple::Httpd::ServiceAdapter
4
- def mount_service(service)
5
- @service = service
6
-
7
- instance_eval do
8
- def dispatch!
9
- ::Simple::Service.with_context(context)
10
- super
11
- ensure
12
- ::Simple::Service.context = nil
13
- end
3
+ module Simple::Httpd::ServiceIntegration
4
+ class Adapter
5
+ extend Forwardable
14
6
 
15
- yield(service)
7
+ def initialize(simple_service)
8
+ @simple_service = simple_service
16
9
  end
10
+
11
+ def action(action_name)
12
+ ::Simple::Service.action(@simple_service, action_name)
13
+ end
14
+
15
+ def invoke(name, args: {}, flags: {})
16
+ ::Simple::Service.invoke @simple_service, name, args: args, flags: flags
17
+ end
18
+
19
+ def invoke3(name, *args, **flags)
20
+ ::Simple::Service.invoke3 @simple_service, name, *args, **flags
21
+ end
22
+ end
23
+
24
+ def mount_service(service)
25
+ @service = Adapter.new(service)
26
+ yield(@service)
17
27
  ensure
18
28
  @service = nil
19
29
  end
@@ -52,16 +62,18 @@ module Simple::Httpd::ServiceAdapter
52
62
  def install_route(verb, path, opts, &block)
53
63
  if service_route?(verb, path, opts, &block)
54
64
  path, action_name = *path.first
55
- handle_service_route(verb, path, action_name)
65
+ install_service_shortcut(verb, path, action_name)
66
+ elsif @service
67
+ install_service_route(verb, path, opts, &block)
56
68
  else
57
- handle_non_service_route(verb, path, opts, &block)
69
+ install_non_service_route(verb, path, opts, &block)
58
70
  end
59
71
  end
60
72
 
61
- def handle_service_route(verb, path, action_name)
73
+ def install_service_shortcut(verb, path, action_name)
62
74
  # Fetch action's source_location. This also verifies that the action
63
75
  # is defined in the first place.
64
- action = ::Simple::Service.action(@service, action_name)
76
+ action = @service.action(action_name)
65
77
 
66
78
  describe_route!(verb: verb, path: path, source_location: action.source_location)
67
79
 
@@ -72,27 +84,43 @@ module Simple::Httpd::ServiceAdapter
72
84
  # define sinatra route.
73
85
  route(verb, path) do
74
86
  ::Simple::Service.with_context(context) do
75
- result = ::Simple::Service.invoke(service, action_name, args: self.parsed_body, flags: stringified_params)
87
+ result = service.invoke(action_name, args: parsed_body, flags: stringified_params)
76
88
  encode_result(result)
89
+ rescue Exception => e
90
+ Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0,10].join("\n ")}"
91
+ raise
77
92
  end
78
93
  end
79
94
  end
80
95
 
81
- def handle_non_service_route(verb, path, opts, &block)
96
+ def install_service_route(verb, path, opts, &block)
82
97
  describe_route!(verb: verb, path: path, source_location: block.source_location) if block
83
98
 
84
99
  route(verb, path, opts) do
85
- result = instance_eval(&block)
86
- unless headers["Content-Type"]
87
- result = encode_result(result)
100
+ ::Simple::Service.with_context(context) do
101
+ result = instance_eval(&block)
102
+ unless headers["Content-Type"]
103
+ result = encode_result(result)
104
+ end
105
+ result
106
+ rescue Exception => e
107
+ Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0,10].join("\n ")}"
108
+ raise
88
109
  end
89
- result
110
+ end
111
+ end
112
+
113
+ def install_non_service_route(verb, path, opts, &block)
114
+ describe_route!(verb: verb, path: path, source_location: block.source_location) if block
115
+
116
+ route(verb, path, opts) do
117
+ instance_eval(&block)
90
118
  end
91
119
  end
92
120
 
93
121
  module Helpers
94
122
  def stringified_params
95
- params.each_with_object({}) do |(k,v), hsh|
123
+ params.each_with_object({}) do |(k, v), hsh|
96
124
  hsh[k.to_s] = v
97
125
  end
98
126
  end
@@ -105,5 +133,5 @@ module Simple::Httpd::ServiceAdapter
105
133
  end
106
134
  end
107
135
 
108
- ::Simple::Httpd::BaseController.extend(::Simple::Httpd::ServiceAdapter)
109
- ::Simple::Httpd::BaseController.helpers(::Simple::Httpd::ServiceAdapter::Helpers)
136
+ ::Simple::Httpd::BaseController.extend(::Simple::Httpd::ServiceIntegration)
137
+ ::Simple::Httpd::BaseController.helpers(::Simple::Httpd::ServiceIntegration::Helpers)
data/simple-httpd.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |gem|
22
22
  # dependencies
23
23
  gem.add_dependency "neatjson", "~> 0.8.4"
24
24
  gem.add_dependency "sinatra", "~> 2"
25
+ # gem.add_dependency "async_sinatra" #, "~> 2"
25
26
  # gem.add_dependency "sinatra-reloader", "~> 1"
26
27
  gem.add_dependency "expectation", "~> 1"
27
28
  gem.add_dependency "simple-cli", "~> 0.3.5"
data/spec/spec_helper.rb CHANGED
@@ -33,7 +33,9 @@ end
33
33
  Dir.glob("./spec/support/**/*.rb").sort.each { |path| load path }
34
34
 
35
35
  require "simple/httpd"
36
-
36
+ #Simple::Httpd.env = "test"
37
+ if ::Simple::Httpd.env == "development"
38
+ end
37
39
  RSpec.configure do |config|
38
40
  config.run_all_when_everything_filtered = true
39
41
  config.filter_run focus: (ENV["CI"] != "true")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-httpd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-04 00:00:00.000000000 Z
11
+ date: 2019-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neatjson
@@ -87,6 +87,7 @@ executables:
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".envrc"
90
91
  - ".gitignore"
91
92
  - ".rubocop.yml"
92
93
  - ".tm_properties"
@@ -99,7 +100,6 @@ files:
99
100
  - bin/console
100
101
  - bin/rake
101
102
  - bin/rspec
102
- - bin/rubocop
103
103
  - bin/simple-httpd
104
104
  - examples/README.md
105
105
  - examples/ex1.services/ex1_service_module.rb
@@ -127,6 +127,7 @@ files:
127
127
  - lib/simple/httpd/base_controller/debug.rb
128
128
  - lib/simple/httpd/base_controller/error_handling.rb
129
129
  - lib/simple/httpd/base_controller/json.rb
130
+ - lib/simple/httpd/base_controller/origin.rb
130
131
  - lib/simple/httpd/base_controller/request.rb
131
132
  - lib/simple/httpd/base_controller/result.rb
132
133
  - lib/simple/httpd/base_controller/x_processing.rb
@@ -137,9 +138,10 @@ files:
137
138
  - lib/simple/httpd/rack/dynamic_mount.rb
138
139
  - lib/simple/httpd/rack/merger.rb
139
140
  - lib/simple/httpd/rack/static_mount.rb
141
+ - lib/simple/httpd/reloader.rb
140
142
  - lib/simple/httpd/route.rb
141
143
  - lib/simple/httpd/server.rb
142
- - lib/simple/httpd/service_adapter.rb
144
+ - lib/simple/httpd/service_integration.rb
143
145
  - lib/simple/httpd/version.rb
144
146
  - log/.gitkeep
145
147
  - scripts/release
@@ -179,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
181
  - !ruby/object:Gem::Version
180
182
  version: '0'
181
183
  requirements: []
182
- rubygems_version: 3.0.4
184
+ rubygems_version: 3.0.6
183
185
  signing_key:
184
186
  specification_version: 4
185
187
  summary: Super-simple HTTPD server
data/bin/rubocop DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rubocop' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
- Pathname.new(__FILE__).realpath)
14
-
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
16
-
17
- if File.file?(bundle_binstub)
18
- if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
- load(bundle_binstub)
20
- else
21
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
- end
24
- end
25
-
26
- require "rubygems"
27
- require "bundler/setup"
28
-
29
- load Gem.bin_path("rubocop", "rubocop")