simple-httpd 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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