simple-httpd 0.3.0 → 0.3.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/.rubocop.yml +7 -0
  3. data/Gemfile +3 -1
  4. data/VERSION +1 -1
  5. data/bin/simple-httpd +1 -3
  6. data/examples/ex1.services/ex1_service_module.rb +8 -0
  7. data/examples/ex1/root.rb +4 -0
  8. data/examples/ex1/spec.rb +7 -0
  9. data/examples/ex2/info.rb +5 -3
  10. data/examples/ex3/example_service.rb +3 -2
  11. data/lib/simple/httpd.rb +37 -28
  12. data/lib/simple/httpd/base_controller.rb +6 -0
  13. data/lib/simple/httpd/base_controller/build_url.rb +1 -1
  14. data/lib/simple/httpd/base_controller/debug.rb +2 -0
  15. data/lib/simple/httpd/base_controller/error_handling.rb +21 -38
  16. data/lib/simple/httpd/base_controller/json.rb +2 -31
  17. data/lib/simple/httpd/base_controller/request.rb +23 -0
  18. data/lib/simple/httpd/base_controller/result.rb +19 -0
  19. data/lib/simple/httpd/cli.rb +71 -30
  20. data/lib/simple/httpd/helpers.rb +35 -3
  21. data/lib/simple/httpd/mount.rb +66 -0
  22. data/lib/simple/httpd/rack/dynamic_mount.rb +52 -32
  23. data/lib/simple/httpd/rack/static_mount.rb +20 -14
  24. data/lib/simple/httpd/route.rb +79 -0
  25. data/lib/simple/httpd/server.rb +28 -16
  26. data/lib/simple/httpd/service_adapter.rb +108 -0
  27. data/simple-httpd.gemspec +2 -1
  28. data/spec/simple/httpd/base_controller/httpd_cors_spec.rb +8 -3
  29. data/spec/simple/httpd/base_controller/httpd_url_building_spec.rb +17 -0
  30. data/spec/simple/httpd/helpers_spec.rb +25 -8
  31. data/spec/simple/httpd/loading_helpers_spec.rb +15 -0
  32. data/spec/simple/httpd/rspec_httpd_spec.rb +25 -9
  33. data/spec/simple/httpd/services/service_explicit_spec.rb +0 -5
  34. data/spec/simple/httpd/services/sideloading_spec.rb +9 -0
  35. data/spec/spec_helper.rb +2 -3
  36. metadata +31 -12
  37. data/examples/services/example_service.rb +0 -25
  38. data/lib/simple/httpd/mount_spec.rb +0 -106
  39. data/lib/simple/httpd/service.rb +0 -70
  40. data/lib/simple/service.rb +0 -69
  41. data/lib/simple/service/action.rb +0 -78
  42. data/lib/simple/service/context.rb +0 -46
  43. data/spec/simple/httpd/services/service_spec.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2cf16a40a84142155ccfdf2486e3f12d2a2be13429a942660136ba1c7ce5034
4
- data.tar.gz: fe679b913fe4ea849945b797fd949ec4d4f9dc783d7ea252e358060037ec25e9
3
+ metadata.gz: 4a7ef636de1fafcba61a0e8d7ed71a235d9c4700633f8ef8a899028415ffa1c7
4
+ data.tar.gz: 2018dc0e1bd99ec1bdc40524bfe2701be509e252cb6655b21e629e996da22614
5
5
  SHA512:
6
- metadata.gz: 36e023782c8602e0864b1787ee661b1b4c6df8b76ea28889a14acc77116b927c98dd7d720850337b011a7c32ad6694767a776ba92ed772953ebdf3960ff43932
7
- data.tar.gz: 0011d3b37a962c6dd5b1781f5dfd934aef319b8e13033b370fc9f4b240fa921ef06475808d7780072cd6c82675db95103d6c856911dd8a61d4048f8a45430bd3
6
+ metadata.gz: dd3fc097a2342e19b79c087fec69c92db23085c2352d323c3b284e60eaa764543048f731063e0d3c31ad3e136dc1bb2518456c00519f9231c0f3cde57a96f0d2
7
+ data.tar.gz: aff819af94b2b12d8e02c1c966dc9eeb9eb6d3b4a805778d609600d2dc9ff33dccb435983ecf4e1221e5346b899ccd7b358d625756fe26b912bf662b94770226
data/.rubocop.yml CHANGED
@@ -8,6 +8,7 @@ AllCops:
8
8
  - '*.gemspec'
9
9
  - 'Gemfile'
10
10
  - 'Rakefile'
11
+ - 'scripts/*.rb'
11
12
 
12
13
  Metrics/LineLength:
13
14
  Max: 140
@@ -87,3 +88,9 @@ Metrics/ParameterLists:
87
88
 
88
89
  Style/StringLiteralsInInterpolation:
89
90
  Enabled: false
91
+
92
+ Style/DoubleNegation:
93
+ Enabled: false
94
+
95
+ Style/ParallelAssignment:
96
+ Enabled: false
data/Gemfile CHANGED
@@ -6,12 +6,14 @@ gemspec
6
6
  # --- Local overrides for runtime dependencies ------------------------------
7
7
 
8
8
  # gem "simple-cli", path: "../simple-cli"
9
+ # gem "simple-service", path: "../simple-service"
9
10
 
10
11
  # --- Development and test dependencies ------------------------------
11
12
 
12
13
  group :development, :test do
13
- gem "rspec-httpd", "~> 0.3.0"
14
+ gem "rspec-httpd", "~> 0.3.2"
14
15
  # gem "rspec-httpd", path: "../rspec-httpd"
16
+ # # gem "simple-http", path: "../simple-http"
15
17
 
16
18
  gem 'rake', '~> 11'
17
19
  gem 'rspec', '~> 3.7'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
data/bin/simple-httpd CHANGED
@@ -8,6 +8,4 @@ Bundler.setup
8
8
  require "simple/cli"
9
9
  require "simple/httpd/cli"
10
10
 
11
- # run the :main command with these arguments. This switches simple-cli into
12
- # non-subcommand mode.
13
- Simple::Httpd::CLI.run!(:main)
11
+ Simple::CLI.run! Simple::Httpd::CLI
@@ -0,0 +1,8 @@
1
+ # Not a real service, but still loaded automatically when mounting ex1
2
+ module Ex1ServiceModule
3
+ extend self
4
+
5
+ def hello_world
6
+ "hello_world"
7
+ end
8
+ end
data/examples/ex1/root.rb CHANGED
@@ -9,3 +9,7 @@ end
9
9
  get "/exit" do
10
10
  exit 1
11
11
  end
12
+
13
+ get "/sideloaded_service" do
14
+ Ex1ServiceModule.hello_world
15
+ end
@@ -0,0 +1,7 @@
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
data/examples/ex2/info.rb CHANGED
@@ -1,4 +1,6 @@
1
- get "/inspect" do
2
- content_type :text
3
- request.env.map { |key, value| "#{key}=#{value}\n" }.grep(/^[A-Z]/).sort.join
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
4
6
  end
@@ -7,7 +7,8 @@ mount_service ExplicitService do |service|
7
7
  post "/echo/:a" => :explicit_echo
8
8
 
9
9
  put "/echo_context" do
10
- # def echo_context
11
- service.call(:echo_context, parsed_body, params, context: context)
10
+ ::Simple::Service.with_context(context) do
11
+ ::Simple::Service.invoke(service, :echo_context)
12
+ end
12
13
  end
13
14
  end
data/lib/simple/httpd.rb CHANGED
@@ -11,20 +11,29 @@ require "simple/service"
11
11
  require "simple/httpd/helpers"
12
12
  require "simple/httpd/base_controller"
13
13
  require "simple/httpd/version"
14
- require "simple/httpd/mount_spec"
14
+ require "simple/httpd/mount"
15
15
  require "simple/httpd/server"
16
16
 
17
- require "simple/httpd/service"
17
+ require "simple/httpd/service_adapter"
18
18
 
19
19
  class Simple::Httpd
20
20
  SELF = self
21
21
 
22
- def self.logger=(logger)
23
- @logger = logger
22
+ # returns a logger for Simple::Httpd.
23
+ #
24
+ # Initially we default to <tt>::Simple::CLI.logger</tt>. This gives colored
25
+ # logging during loading and mounting. Note that Simple::Httpd::Server builds
26
+ # its own logger instance to to pass that along to the web server.
27
+ def self.logger
28
+ @logger ||= ::Simple::CLI.logger
24
29
  end
25
30
 
26
- def self.logger
27
- @logger ||= ::Logger.new(STDERR, level: ::Logger::INFO)
31
+ def self.custom_logger?
32
+ @logger && @logger != ::Simple::CLI.logger
33
+ end
34
+
35
+ def self.logger=(logger)
36
+ @logger = logger
28
37
  end
29
38
 
30
39
  # Converts the passed in args into a Simple::Httpd application.
@@ -34,43 +43,49 @@ class Simple::Httpd
34
43
  # respond to call/3) it redirects to <tt>Server.listen!</tt> right
35
44
  # away - this way this method can be used as a helper method
36
45
  # to easily start a Rack server.
37
- def self.listen!(*mount_specs, environment: "development", host: nil, port:, logger: nil, &block)
46
+ def self.listen!(*mounts, environment: "development", host: nil, port:, &block)
38
47
  # If there is no argument but a block use the block as a rack server
39
48
  if block
40
- raise ArgumentError, "Can't deal w/block *and* mount_specs" unless mount_specs.empty?
49
+ raise ArgumentError, "Can't deal w/block *and* mounts" unless mounts.empty?
41
50
 
42
51
  app = block
43
- elsif mount_specs.length == 1 && mount_specs.first.respond_to?(:call)
52
+ elsif mounts.length == 1 && mounts.first.respond_to?(:call)
44
53
  # there is one argument, and that looks like a Rack app: return that.
45
- app = mount_specs.first
54
+ app = mounts.first
46
55
  else
47
56
  # Build a Httpd app, and listen
48
- app = build(*mount_specs)
57
+ app = build(*mounts)
49
58
  app.rack
50
59
  end
51
60
 
52
- Server.listen!(app, environment: environment, host: host, port: port, logger: logger)
61
+ Server.listen!(app, environment: environment, host: host, port: port)
53
62
  end
54
63
 
55
64
  # Converts the passed in arguments into a Simple::Httpd application.
56
65
  #
57
66
  # For a description of mounts see <tt>#add</tt>
58
- def self.build(*mount_specs)
59
- new(*mount_specs)
67
+ def self.build(*mounts)
68
+ new(*mounts)
60
69
  end
61
70
 
62
71
  private
63
72
 
64
73
  # Builds a Simple::Httpd application.
65
- def initialize(*mount_specs)
66
- @mount_specs = []
67
- mount_specs.map do |mount_spec|
68
- mount(mount_spec, at: nil)
74
+ def initialize(*mounts)
75
+ @mounts = []
76
+ mounts.map do |mount|
77
+ mount(mount, at: nil)
69
78
  end
70
79
  end
71
80
 
72
81
  public
73
82
 
83
+ def route_descriptions
84
+ @mounts.inject([]) do |ary, mount|
85
+ ary.concat mount.route_descriptions
86
+ end
87
+ end
88
+
74
89
  # Adds one or more mount_points
75
90
  #
76
91
  # Each entry in mounts can be either:
@@ -79,10 +94,10 @@ class Simple::Httpd
79
94
  # - a string denoting a mount_point, e.g. "path/to/root:/")
80
95
  # - a string denoting a "/" mount_point (e.g. "path", which is shorthand for "path:/")
81
96
  #
82
- def mount(mount_spec, at: nil)
97
+ def mount(mount, at: nil)
83
98
  raise ArgumentError, "Cannot mount onto an already built app" if built?
84
99
 
85
- @mount_specs << MountSpec.build(mount_spec, at: at)
100
+ @mounts << Mount.build(mount, at: at)
86
101
  end
87
102
 
88
103
  extend Forwardable
@@ -97,8 +112,8 @@ class Simple::Httpd
97
112
  def build_rack
98
113
  uri_map = {}
99
114
 
100
- @mount_specs.group_by(&:mount_point).map do |mount_point, mount_specs|
101
- apps = mount_specs.map(&:build_rack_apps).flatten
115
+ @mounts.group_by(&:mount_point).map do |mount_point, mounts|
116
+ apps = mounts.map(&:build_rack_apps).flatten
102
117
  uri_map[mount_point] = Rack.merge(apps)
103
118
  end
104
119
 
@@ -108,10 +123,4 @@ class Simple::Httpd
108
123
  def built?
109
124
  @rack != nil
110
125
  end
111
-
112
- public
113
-
114
- def listen!(environment:, port:, logger:)
115
- SELF.listen!(rack, environment: environment, port: port, logger: logger)
116
- end
117
126
  end
@@ -17,6 +17,12 @@ class Simple::Httpd::BaseController < Sinatra::Base
17
17
  end
18
18
  end
19
19
 
20
+ require_relative "./route"
21
+
22
+ class Simple::Httpd::BaseController
23
+ extend ::Simple::Httpd::RouteDescriptions
24
+ end
25
+
20
26
  Dir.chdir __dir__ do
21
27
  Dir.glob("base_controller/*.rb").sort.each do |file|
22
28
  require_relative file
@@ -28,7 +28,7 @@ class Simple::Httpd::BaseController
28
28
  private
29
29
 
30
30
  def build_url_query(params)
31
- params = params.reject { |_k, v| v.nil? || v.empty? }
31
+ params = params.reject { |_k, v| v.nil? || v.to_s.empty? }
32
32
  return nil if params.empty?
33
33
 
34
34
  params.map { |k, value| "#{k}=#{escape(value.to_s)}" }.join("&")
@@ -1,6 +1,8 @@
1
1
  class Simple::Httpd::BaseController
2
2
  helpers do
3
3
  def debug(data)
4
+ require "pp"
5
+
4
6
  content_type "text/plain"
5
7
  halt data.pretty_inspect
6
8
  end
@@ -1,7 +1,5 @@
1
1
  require_relative "./json"
2
2
 
3
- # rubocop:disable Metrics/ClassLength
4
-
5
3
  class Simple::Httpd::BaseController
6
4
  H = ::Simple::Httpd::Helpers
7
5
 
@@ -9,8 +7,6 @@ class Simple::Httpd::BaseController
9
7
  set :dump_errors, false
10
8
  set :raise_errors, false
11
9
 
12
- set :raise_errors, true if ENV["RACK_ENV"] == "test"
13
-
14
10
  private
15
11
 
16
12
  def stringify_hash(hsh)
@@ -127,19 +123,27 @@ class Simple::Httpd::BaseController
127
123
 
128
124
  # -- print unspecified errors.
129
125
 
130
- error do |exc|
131
- content_type :text
132
- message = <<~MSG
133
- === #{exc.class.name} =====================
134
- #{exc.message.chomp}
135
-
136
- #{filtered_backtrace(exc)}
137
- ==================================================================
138
- MSG
139
-
140
- STDERR.puts message
141
- status 500
142
- "\n#{message}\n"
126
+ if ENV["RACK_ENV"] == "production"
127
+ error do |exc|
128
+ content_type :text
129
+ status 500
130
+ exc.class.name
131
+ end
132
+ else
133
+ error do |exc|
134
+ content_type :text
135
+ message = <<~MSG
136
+ === #{exc.class.name} =====================
137
+ #{exc.message.chomp}
138
+
139
+ #{H.filtered_stacktrace(exc.backtrace).join("\n")}
140
+ ==================================================================
141
+ MSG
142
+
143
+ STDERR.puts message
144
+ status 500
145
+ "\n#{message}\n"
146
+ end
143
147
  end
144
148
 
145
149
  private
@@ -152,25 +156,4 @@ class Simple::Httpd::BaseController
152
156
  exc.message
153
157
  # "#{exc.message}, from #{exc.backtrace.join("\n\t")}"
154
158
  end
155
-
156
- def remove_wd(str)
157
- @wd ||= Dir.getwd
158
-
159
- if str.start_with?(@wd)
160
- str[(@wd.length + 1)..-1]
161
- else
162
- str
163
- end
164
- end
165
-
166
- def filtered_backtrace(exc, count: 20)
167
- lines = exc.backtrace.map do |line|
168
- next "...\n" if line =~ /\.rvm\b/
169
-
170
- "#{remove_wd(line)}\n"
171
- end
172
-
173
- s = lines[0, count].join("")
174
- s.gsub(/(\.\.\.\n)+/, " ... (lines removed) ...\n")
175
- end
176
159
  end
@@ -12,42 +12,13 @@ class Simple::Httpd::BaseController
12
12
 
13
13
  configure :development, :test do
14
14
  begin
15
- @@neatjson = true
16
15
  require "neatjson"
17
16
  rescue LoadError
18
- @@neatjson = false
17
+ :nop
19
18
  end
20
19
 
21
20
  def generate_json(result)
22
- if @@neatjson
23
- JSON.neat_generate(result)
24
- else
25
- JSON.pretty_generate(result)
26
- end
27
- end
28
- end
29
-
30
- public
31
-
32
- def parsed_body
33
- return @parsed_body if defined? @parsed_body
34
-
35
- @parsed_body = parse_body
36
- rescue RuntimeError => e
37
- raise ArgumentError, e.to_s
38
- end
39
-
40
- private
41
-
42
- def parse_body
43
- case request.media_type
44
- when "application/json"
45
- request.body.rewind
46
- body = request.body.read
47
- body == "" ? {} : JSON.parse(body)
48
- else
49
- # parses form data
50
- request.POST
21
+ JSON.respond_to?(:neat_generate) ? JSON.neat_generate(result) : JSON.pretty_generate(result)
51
22
  end
52
23
  end
53
24
  end
@@ -0,0 +1,23 @@
1
+ class Simple::Httpd::BaseController
2
+ def parsed_body
3
+ return @parsed_body if defined? @parsed_body
4
+
5
+ @parsed_body = parse_body
6
+ rescue RuntimeError => e
7
+ raise ArgumentError, e.to_s
8
+ end
9
+
10
+ private
11
+
12
+ def parse_body
13
+ case request.media_type
14
+ when "application/json"
15
+ request.body.rewind
16
+ body = request.body.read
17
+ body == "" ? {} : JSON.parse(body)
18
+ else
19
+ # parses form data
20
+ request.POST
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
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
17
+ end
18
+ end
19
+ end