simple-httpd 0.3.5 → 0.4.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: 00457b4ed11c8a501e43a4c4826ef6d78722b072ffff0bab1b0c609c797e14f7
4
- data.tar.gz: ed35d788fba032b31b971f29e07b23cf490ffc1d96a3aff9369bc812bda22dde
3
+ metadata.gz: 02564f089db886a8701424a42bedbe88bb6401febc4eb397b5630560bd82595a
4
+ data.tar.gz: 139371909bee1f7045f51d5ad6a0ee4b18f080eb461e8a8770c16ad506fb7e73
5
5
  SHA512:
6
- metadata.gz: 0d57c201cad87a16655eb6e05a4b527176603ab063d08878b44711741babd3fb62140224b5e7cfd0c6ff3e2937c5d177c6ffcb4d88143903f99d36bd5d937f02
7
- data.tar.gz: a55d03f273b5a634262a55916c15690bf845641f69af2217a82d4a778b84af089cdb3722df89c25d4d1d847a2654f4c858c141900115e895c8fa3d8ef55dbc4b
6
+ metadata.gz: 52fdf766ce5cd92ef52426f739c4fb3ec3af76703c6e2190bc20873d0a3f01c28ed6e0f22aa3d79870fb8e13d755b61cf0280935747429d693278d175036766d
7
+ data.tar.gz: 7b88cdc01ea262105f25dbdb5fcd28c75d464cd5d0e1bda597e51002355310f2dc96ccecedd64bb5e1266306e01fcadfc6ea98609352b9a56eb1db2a0d1ce298
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.3
2
+ TargetRubyVersion: 2.5
3
3
  Exclude:
4
4
  - 'spec/**/*'
5
5
  - 'test/**/*'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.7
data/README.md CHANGED
@@ -30,13 +30,9 @@ They become available at the location specified by their filename and extension.
30
30
 
31
31
  ### Dynamic assets
32
32
 
33
- Each mounted directory which contains ruby source files is converted into a sinatra application, which consists of a root configuration and controllers for each action file.
33
+ Each mounted directory might contain a "routes.rb" ruby source file which is loaded in the context of a Sinatra controller to set up routes. Example:
34
34
 
35
- Ruby files ending in `_helpers.rb`, e.g. `examples/ex1/ex1_helpers.rb` are executed in the context of a directory tree's root controller and provide functionality available in all action files. Typically they do not implement HTTP handlers themselves.
36
-
37
- All other ruby files implement HTTP handlers in typical sinatra fashion:
38
-
39
- # in v2/jobs.rb
35
+ # in v2/routes.rb
40
36
  get "/queue/:id/events" do
41
37
  events = [
42
38
  { job_id: params[:id], id: "event1" },
@@ -46,16 +42,10 @@ All other ruby files implement HTTP handlers in typical sinatra fashion:
46
42
  json events
47
43
  end
48
44
 
49
- If this snippet is contained in a file `v2/jobs.rb` and the `v2` directory is mounted into `api/v2`, the snipped implements the handler for, for example, `GET /api/v2/jobs/queue/123/events`. In other words, the handler implement in the source file works on paths relative to a path combining the mount location and the file name.
50
-
51
- To implement a action on the mountpoint itself one uses the `root.rb` file. The following
52
-
53
- # in v2/root.rb
54
- get "/" do
55
- json version: "123"
56
- end
45
+ Ruby files below `./helpers` in the dynamically loaded directory is loaded as a helper file when setting up a dynamic mount, e.g. `examples/ex1/helpers/ex1_helpers.rb` are executed in the context of a directory tree's root controller and provide functionality
46
+ available in the `routes.rb` file.
57
47
 
58
- would implement `GET /api/v2`.
48
+ [TODO] describe service usage.
59
49
 
60
50
  ## Command line usage
61
51
 
@@ -77,8 +67,7 @@ The arguments `ex1` and `ex2` serve at the `/` location. This notation really is
77
67
  port = 12345
78
68
 
79
69
  app = ::Simple::Httpd.build("/" => httpd_root_dir)
80
- ::Simple::Httpd.listen! app, port: port,
81
- logger: ::Logger.new(STDERR)
70
+ ::Simple::Httpd.listen! app, port: port, logger: ::Logger.new(STDERR)
82
71
 
83
72
 
84
73
  ## The example application
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.5
1
+ 0.4.0
data/examples/README.md CHANGED
@@ -18,14 +18,14 @@ The following explanations assume you started a server with the configuration me
18
18
 
19
19
  This directory currently contains these files:
20
20
 
21
- - ex1/root.rb
21
+ - ex1/routes.rb
22
22
  - ex1/ex1_helpers.rb
23
23
  - ex2/helpers.rb
24
- - ex2/root.rb
24
+ - ex2/routes.rb
25
25
  - ex2/info.rb
26
26
  - ex2/ex2_helpers.rb
27
27
  - ex2/README.txt
28
- - v2/root.rb
28
+ - v2/routes.rb
29
29
  - v2/jobs.rb
30
30
  - v2/v2_helpers.rb
31
31
  - v2/api.js
@@ -34,8 +34,8 @@ This directory currently contains these files:
34
34
 
35
35
  The following lists some routes and where they are implemented:
36
36
 
37
- GET "/" .. in ex1/root.rb
38
- GET "/debug" .. in ex2/root.rb
37
+ GET "/" .. in ex1/routes.rb
38
+ GET "/debug" .. in ex2/routes.rb
39
39
  GET "/info/inspect" .. in ex2/info.rb
40
- GET "/api/v2/" .. in v2/root.rb
40
+ GET "/api/v2/" .. in v2/routes.rb
41
41
  GET "/api/v2/jobs/:id/events" .. in v2/jobs.rb
@@ -21,3 +21,11 @@ end
21
21
  get "/sideloaded_service" do
22
22
  Ex1ServiceModule.hello_world
23
23
  end
24
+
25
+ get "/spec/full_url" do
26
+ full_url "foo", search: "s", page: 1
27
+ end
28
+
29
+ get "/spec/url" do
30
+ url "foo", search: "s", page: 1
31
+ end
File without changes
@@ -0,0 +1,22 @@
1
+ get "/debug" do
2
+ debug params
3
+ end
4
+
5
+ [:get, :post, :put, :delete, :head].each do |verb|
6
+ send verb, "/info/inspect" do
7
+ content_type :text
8
+ request.env.map { |key, value| "#{key}=#{value}\n" }.grep(/^[A-Z]/).sort.join
9
+ end
10
+ end
11
+
12
+ get "/helpers/ex1" do
13
+ ex1_helper
14
+ rescue NameError
15
+ not_found! "ex1_helper cannot be run"
16
+ end
17
+
18
+ get "/helpers/ex2" do
19
+ ex2_helper
20
+ rescue NameError
21
+ not_found! "ex2_helper cannot be run"
22
+ end
File without changes
@@ -1,9 +1,13 @@
1
- get "/info" do
1
+ get "/" do
2
+ json version: "v2"
3
+ end
4
+
5
+ get "/jobs/info" do
2
6
  content_type :text
3
7
  "info"
4
8
  end
5
9
 
6
- get "/:id/events" do
10
+ get "/jobs/:id/events" do
7
11
  events = [
8
12
  { job_id: params[:id], id: "event1" },
9
13
  { job_id: params[:id], id: "event2" }
@@ -5,7 +5,6 @@ require "expectation"
5
5
  # existing static files.
6
6
  class Simple::Httpd::Rack::DynamicMount
7
7
  H = ::Simple::Httpd::Helpers
8
- Rack = ::Simple::Httpd::Rack
9
8
 
10
9
  extend Forwardable
11
10
 
@@ -27,13 +26,15 @@ class Simple::Httpd::Rack::DynamicMount
27
26
  @mount_point = mount_point
28
27
  @path = path.gsub(/\/\z/, "") # remove trailing "/"
29
28
 
30
- setup_paths!
31
29
  ::Simple::Httpd::Reloader.attach self, paths: service_files, reloading_instance: nil
32
30
 
33
- @root_controller = build_root_controller # also loads helpers
34
- @url_map = build_url_map
31
+ @rack_app = H.subclass ::Simple::Httpd::BaseController,
32
+ paths: helper_files + ["#{path}/routes.rb"],
33
+ description: "<controller:#{H.shorten_path(path)}>"
35
34
 
36
- @rack_app = ::Rack::URLMap.new(@url_map)
35
+ @rack_app.route_descriptions.each do |route|
36
+ describe_route! route.prefix(@mount_point)
37
+ end
37
38
  end
38
39
 
39
40
  # RouteDescriptions are being built during build_url_map
@@ -41,54 +42,15 @@ class Simple::Httpd::Rack::DynamicMount
41
42
 
42
43
  private
43
44
 
44
- def logger
45
- ::Simple::Httpd.logger
46
- end
47
-
48
- def setup_paths!
49
- @source_paths = Dir.glob("#{path}/**/*.rb")
50
- @helper_paths, @controller_paths = @source_paths.partition { |str| /_helper(s?)\.rb$/ =~ str }
51
-
52
- logger.info "#{path}: found #{@source_paths.count} sources, #{@helper_paths.count} helpers"
53
- end
54
-
55
45
  def service_files
56
- @service_files ||= _service_files
57
- end
58
-
59
- def _service_files
60
- return [] if path == "." # i.e. mounting current directory
61
-
62
- service_path = "#{path}.services"
63
- return [] unless Dir.exist?(service_path)
64
-
65
- service_files = Dir.glob("#{service_path}/**/*.rb").sort
66
- logger.info "#{service_path}: loading #{service_files.count} service file(s)"
46
+ service_files = Dir.glob("#{path}/services/**/*.rb").sort
47
+ ::Simple::Httpd.logger.info "#{path}: loading #{service_files.count} service file(s)" if service_files.count > 0
67
48
  service_files
68
49
  end
69
50
 
70
- # wraps all helpers into a Simple::Httpd::BaseController subclass
71
- def build_root_controller
72
- H.subclass ::Simple::Httpd::BaseController,
73
- paths: @helper_paths.sort,
74
- description: "<root controller: #{H.shorten_path path}>"
75
- end
76
-
77
- def build_url_map
78
- @controller_paths.sort.each_with_object({}) do |absolute_path, hsh|
79
- relative_path = absolute_path[(path.length)..-1]
80
-
81
- relative_mount_point = relative_path == "/root.rb" ? "/" : relative_path.gsub(/\.rb$/, "")
82
- controller_class = H.subclass @root_controller,
83
- paths: absolute_path,
84
- description: "<controller:#{H.shorten_absolute_path(absolute_path)}>"
85
-
86
- controller_class.route_descriptions.each do |route|
87
- route = route.prefix(@mount_point, relative_mount_point)
88
- describe_route! route
89
- end
90
-
91
- hsh.update relative_mount_point => controller_class
92
- end
51
+ def helper_files
52
+ helper_files = Dir.glob("#{path}/helpers/**/*.rb").sort
53
+ ::Simple::Httpd.logger.info "#{path}: loading #{helper_files.count} helper file(s)" if helper_files.count > 0
54
+ helper_files
93
55
  end
94
56
  end
@@ -50,12 +50,24 @@ module Simple::Httpd::Reloader
50
50
  "#{verb} #{H.shorten_path path}"
51
51
  end
52
52
 
53
- if @__reloading_instance__
54
- @__reloading_instance__.instance_eval File.read(path), path, 1
55
- else
56
- load path
53
+ silence_warnings do
54
+ if @__reloading_instance__
55
+ @__reloading_instance__.instance_eval File.read(path), path, 1
56
+ else
57
+ load path
58
+ end
57
59
  end
58
60
 
59
61
  @__source_mtimes_by_path__[path] = mtime
60
62
  end
63
+
64
+ def silence_warnings(&block)
65
+ _ = block
66
+
67
+ warn_level = $VERBOSE
68
+ $VERBOSE = nil
69
+ yield
70
+ ensure
71
+ $VERBOSE = warn_level
72
+ end
61
73
  end
@@ -1,3 +1,6 @@
1
+ # rubocop:disable Lint/RescueException
2
+ # rubocop:disable Metrics/AbcSize
3
+
1
4
  require "simple-service"
2
5
 
3
6
  module Simple::Httpd::ServiceIntegration
@@ -86,8 +89,11 @@ module Simple::Httpd::ServiceIntegration
86
89
  ::Simple::Service.with_context(context) do
87
90
  result = service.invoke(action_name, args: parsed_body, flags: stringified_params)
88
91
  encode_result(result)
92
+ rescue Errno::ENOENT => e
93
+ Simple::Httpd.logger.warn e.to_s
94
+ raise
89
95
  rescue Exception => e
90
- Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0,10].join("\n ")}"
96
+ Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0, 10].join("\n ")}"
91
97
  raise
92
98
  end
93
99
  end
@@ -103,8 +109,11 @@ module Simple::Httpd::ServiceIntegration
103
109
  result = encode_result(result)
104
110
  end
105
111
  result
112
+ rescue Errno::ENOENT => e
113
+ Simple::Httpd.logger.warn e.to_s
114
+ raise
106
115
  rescue Exception => e
107
- Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0,10].join("\n ")}"
116
+ Simple::Httpd.logger.warn "#{e}, from\n #{e.backtrace[0, 10].join("\n ")}"
108
117
  raise
109
118
  end
110
119
  end
@@ -8,7 +8,7 @@ describe Simple::Httpd do
8
8
  end
9
9
 
10
10
  describe "root routing" do
11
- it "resolves routes from root.rb" do
11
+ it "resolves routes from routes.rb" do
12
12
  http.get "/"
13
13
  expect_response "root"
14
14
  end
@@ -1,13 +1,13 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe "dynamic mounting" do
4
- it "resolves routes from root.rb" do
4
+ it "resolves routes from routes.rb" do
5
5
  http.get "/"
6
6
  expect_response "root"
7
7
  end
8
8
 
9
9
  # mounting not at root level
10
- it "gets deep route from a root.rb file not mounted at /" do
10
+ it "gets deep route from a routes.rb file not mounted at /" do
11
11
  http.get "/api/v2"
12
12
  expect(http.content).to eq("version" => "v2")
13
13
  expect(http.response.headers["content-type"]).to match(/application\/json/)
@@ -19,13 +19,13 @@ describe "dynamic mounting" do
19
19
  expect(http.response.headers["content-type"]).to match(/application\/javascript/)
20
20
  end
21
21
 
22
- it "gets deep route from non-root.rb file" do
22
+ it "gets deep route from non-routes.rb file" do
23
23
  http.get "/api/v2/jobs/info"
24
24
  expect_response "info"
25
25
  expect(http.response.headers["content-type"]).to match(/text\/plain/)
26
26
  end
27
27
 
28
- it "gets deep route with params from non-root.rb file" do
28
+ it "gets deep route with params from non-routes.rb file" do
29
29
  http.get "/api/v2/jobs/12/events"
30
30
  expect(http.response.headers["content-type"]).to match(/application\/json/)
31
31
  expect(http.content).to eq([{ "job_id" => "12", "id" => "event1" }, { "job_id" => "12", "id" => "event2" }])
@@ -7,7 +7,7 @@ describe "static mounting" do
7
7
  end
8
8
 
9
9
  it "does not return a forbidden static file" do
10
- http.get "/root.rb"
10
+ http.get "/routes.rb"
11
11
  expect_response 404
12
12
  end
13
13
  end
data/spec/spec_helper.rb CHANGED
@@ -16,7 +16,7 @@ HTTPD_COMMAND = <<~CMD
16
16
  --environment=test
17
17
  examples/ex1
18
18
  examples/ex2
19
- examples/ex3
19
+ examples/ex3:example_service
20
20
  examples/v2:api/v2
21
21
  --services=examples/services
22
22
  # 2> log/test.log
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-httpd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
@@ -90,6 +90,7 @@ files:
90
90
  - ".envrc"
91
91
  - ".gitignore"
92
92
  - ".rubocop.yml"
93
+ - ".ruby-version"
93
94
  - ".tm_properties"
94
95
  - Gemfile
95
96
  - Makefile
@@ -102,21 +103,18 @@ files:
102
103
  - bin/rspec
103
104
  - bin/simple-httpd
104
105
  - examples/README.md
105
- - examples/ex1.services/ex1_service_module.rb
106
106
  - examples/ex1/ex1_helpers.rb
107
- - examples/ex1/root.rb
108
- - examples/ex1/spec.rb
107
+ - examples/ex1/routes.rb
108
+ - examples/ex1/services/ex1_service_module.rb
109
109
  - examples/ex2/README.txt
110
- - examples/ex2/ex2_helpers.rb
111
- - examples/ex2/helpers.rb
112
- - examples/ex2/info.rb
113
- - examples/ex2/root.rb
114
- - examples/ex3/example_service.rb
110
+ - examples/ex2/helpers/ex2_helpers.rb
111
+ - examples/ex2/helpers/helpers.rb
112
+ - examples/ex2/routes.rb
113
+ - examples/ex3/routes.rb
115
114
  - examples/services/explicit_example_service.rb
116
115
  - examples/v2/api.js
117
- - examples/v2/jobs.rb
118
- - examples/v2/root.rb
119
- - examples/v2/v2_helpers.rb
116
+ - examples/v2/helpers/v2_helpers.rb
117
+ - examples/v2/routes.rb
120
118
  - lib/simple-httpd.rb
121
119
  - lib/simple-service.rb
122
120
  - lib/simple.rb
data/examples/ex1/spec.rb DELETED
@@ -1,7 +0,0 @@
1
- get "/full_url" do
2
- full_url "foo", search: "s", page: 1
3
- end
4
-
5
- get "/url" do
6
- url "foo", search: "s", page: 1
7
- end
@@ -1,15 +0,0 @@
1
- get "/ex1" do
2
- begin
3
- ex1_helper
4
- rescue NameError
5
- not_found! "ex1_helper cannot be run"
6
- end
7
- end
8
-
9
- get "/ex2" do
10
- begin
11
- ex2_helper
12
- rescue NameError
13
- not_found! "ex2_helper cannot be run"
14
- end
15
- end
data/examples/ex2/info.rb DELETED
@@ -1,6 +0,0 @@
1
- [:get, :post, :put, :delete, :head].each do |verb|
2
- send verb, "/inspect" do
3
- content_type :text
4
- request.env.map { |key, value| "#{key}=#{value}\n" }.grep(/^[A-Z]/).sort.join
5
- end
6
- end
data/examples/ex2/root.rb DELETED
@@ -1,3 +0,0 @@
1
- get "/debug" do
2
- debug params
3
- end
data/examples/v2/root.rb DELETED
@@ -1,3 +0,0 @@
1
- get "/" do
2
- json version: "v2"
3
- end