simple-httpd 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e3943911c33876d60f023ec58fab2d875eb9e2b0b23c3649f0d7601e8b1f304c
4
+ data.tar.gz: 7ff0ef4341bb717ed1b6fafc7339335aa738a660638df64d1b5eba5ec6174a2c
5
+ SHA512:
6
+ metadata.gz: ca193f4c704a1d94f2cc193f953c259c97164dcc28eae9a75347b72e18b31447cf1222df51c36109c129827e09e65e9ad0d3c098fb63a41597052c86cbf08277
7
+ data.tar.gz: 27045e31517c41301ad6ce9e43c8bad59b90e4e099b64c115a9061ba6eed6b28d238e1a117a65efe85fa3fd0d1d3131a369ffd98cf1beff4b98ceabf94854aa6
@@ -0,0 +1,12 @@
1
+ coverage
2
+ rdoc
3
+ pkg
4
+ log/test.log
5
+ .rspec.data
6
+ Gemfile.lock
7
+ .rake_t_cache
8
+ .rspec.status
9
+ .DS_Store
10
+ tmp
11
+ .byebug_history
12
+ .bundle/config
@@ -0,0 +1,80 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Exclude:
4
+ - 'spec/**/*'
5
+ - 'test/**/*'
6
+ - 'bin/**/*'
7
+ - 'tasks/release.rake'
8
+ - '*.gemspec'
9
+ - 'Gemfile'
10
+ - 'Rakefile'
11
+
12
+ Metrics/LineLength:
13
+ Max: 140
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+
18
+ Style/SpecialGlobalVars:
19
+ Enabled: false
20
+
21
+ Style/StringLiterals:
22
+ EnforcedStyle: double_quotes
23
+ ConsistentQuotesInMultiline: false
24
+
25
+ Style/ClassAndModuleChildren:
26
+ Enabled: false
27
+
28
+ Style/ModuleFunction:
29
+ Enabled: false
30
+
31
+ Style/FrozenStringLiteralComment:
32
+ Enabled: false
33
+
34
+ Style/Documentation:
35
+ Enabled: false
36
+
37
+ Style/MutableConstant:
38
+ Enabled: false
39
+
40
+ Style/FormatStringToken:
41
+ Enabled: false
42
+
43
+ Style/Lambda:
44
+ Enabled: false
45
+
46
+ Style/SymbolArray:
47
+ Enabled: false
48
+
49
+ Style/FormatString:
50
+ Enabled: false
51
+
52
+ Style/PercentLiteralDelimiters:
53
+ Enabled: false
54
+
55
+ Lint/MissingCopEnableDirective:
56
+ Enabled: false
57
+
58
+ Style/NumericPredicate:
59
+ Enabled: false
60
+
61
+ Style/RegexpLiteral:
62
+ Enabled: false
63
+
64
+ Style/ClassVars:
65
+ Enabled: false
66
+
67
+ Style/ConditionalAssignment:
68
+ Enabled: false
69
+
70
+ Style/IfUnlessModifier:
71
+ Enabled: false
72
+
73
+ Style/PerlBackrefs:
74
+ Enabled: false
75
+
76
+ Style/TrailingUnderscoreVariable:
77
+ Enabled: false
78
+
79
+ Style/StderrPuts:
80
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'byebug'
4
+ # Specify your gem's dependencies in {gemname}.gemspec
5
+ gemspec
@@ -0,0 +1,3 @@
1
+ # simple-httpd
2
+
3
+ [TODO]
@@ -0,0 +1 @@
1
+ Dir.glob("tasks/*.rake").each { |r| import r }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ Bundler.require
5
+ require "simple-httpd"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' 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("rake", "rake")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' 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("rspec-core", "rspec")
@@ -0,0 +1,29 @@
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")
@@ -0,0 +1,3 @@
1
+ # rubocop:disable Naming/FileName
2
+
3
+ require "simple/httpd"
@@ -0,0 +1,2 @@
1
+ module Simple
2
+ end
@@ -0,0 +1,43 @@
1
+ module Simple
2
+ end
3
+
4
+ module Simple::Httpd
5
+ end
6
+
7
+ require "simple/httpd/version"
8
+ require "simple/httpd/app"
9
+ require "simple/httpd/base_controller"
10
+
11
+ module Simple::Httpd
12
+ extend self
13
+
14
+ def build_rack(base_controller, logger:)
15
+ App.new(base_controller, logger: logger)
16
+ end
17
+
18
+ def listen!(app, environment:, port:)
19
+ expect! port => 80..60_000
20
+
21
+ logger = app.logger
22
+ logger.info "Starting httpd server on http://0.0.0.0:#{port}/"
23
+
24
+ app = Rack::Lint.new(app) if environment != "production"
25
+
26
+ # re/AccessLog: the AccessLog setting points WEBrick's access logging to the
27
+ # NullLogger object.
28
+ #
29
+ # Instead we'll use a combination of Rack::CommonLogger (see Simple::Httpd.app),
30
+ # and sinatra's logger (see Simple::Httpd::BaseController).
31
+ Rack::Server.start app: app,
32
+ Port: port,
33
+ environment: environment,
34
+ Logger: logger,
35
+ AccessLog: [[NullLogger, ""]]
36
+ end
37
+
38
+ module NullLogger # :nodoc:
39
+ extend self
40
+
41
+ def <<(msg); end
42
+ end
43
+ end
@@ -0,0 +1,84 @@
1
+ class Simple::Httpd::App
2
+ end
3
+
4
+ require_relative "app/file_server"
5
+
6
+ # The Simple::Httpd::App implements a Rack compatible app, which serves
7
+ # HTTP requests via a set of controllers inherited from a base controller
8
+ # class.
9
+ #
10
+ # The individual routes are determined from the controller class names:
11
+ # assuming we have a controller class Foo::Bar::BazController inheriting
12
+ # from Foo::BaseController will serve the /bar/baz routes.
13
+ #
14
+ # Additional static routes can be configured by calling "mount_directory!!"
15
+ # on the app object.
16
+ class Simple::Httpd::App
17
+ extend Forwardable
18
+ delegate call: :@app
19
+
20
+ attr_reader :logger
21
+
22
+ #
23
+ # Builds a App object
24
+ def initialize(base_controller, logger:)
25
+ raise unless logger
26
+
27
+ @base_controller = base_controller
28
+ @logger = logger
29
+ @file_mounts = []
30
+
31
+ @app = Rack::URLMap.new(controllers_url_map)
32
+ end
33
+
34
+ def mount_directory!(url:, path:)
35
+ @logger.debug "#{path}: mount directory #{path}"
36
+ @app = FileServer.new(@app, url_prefix: url, root: path)
37
+ end
38
+
39
+ private
40
+
41
+ # Find all controllers inheriting off base_controller and return
42
+ # a URL map, based on the names of the controllers.
43
+ def controllers_url_map
44
+ controller_by_mountpoint = ObjectSpace
45
+ .each_object(Class)
46
+ .select { |klass| klass < @base_controller }
47
+ .map { |controller| [mountpoint(controller), controller] }
48
+ .reject { |mountpoint, _controller| mountpoint.nil? }
49
+
50
+ controller_by_mountpoint
51
+ .sort_by { |path, _controller| path }
52
+ .each { |path, controller| logger.debug "#{path}: mount #{controller}" }
53
+
54
+ Hash[controller_by_mountpoint]
55
+ end
56
+
57
+ def mountpoint(controller)
58
+ return unless controller.name.end_with?("Controller")
59
+
60
+ relative_controller_name = relative_controller_name(controller)
61
+ return "/" if relative_controller_name == "RootController"
62
+
63
+ "/" + relative_controller_name.underscore.gsub(/_controller$/, "")
64
+ end
65
+
66
+ # With a controller of Postjob::FooBarController returns FooBarController
67
+ # (depending on the base_controller)
68
+ def relative_controller_name(controller)
69
+ controller_name = controller.name
70
+ if controller_name.start_with?(base_controller_namespace)
71
+ controller_name[base_controller_namespace.length..-1]
72
+ else
73
+ controller_name
74
+ end
75
+ end
76
+
77
+ # With a base_controller of Postjob::BaseController this returns "Postjob"
78
+ def base_controller_namespace
79
+ @base_controller_namespace ||= begin
80
+ base_controller_name = @base_controller.name
81
+ base_controller_name.gsub(/::BaseController$/, "::")
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ class Simple::Httpd::App::FileServer
2
+ # A simple file server middleware
3
+ def initialize(app, url_prefix:, root:)
4
+ @app = app
5
+ @url_prefix = File.join("/", url_prefix, "/")
6
+ @file_server = Rack::File.new(root)
7
+ end
8
+
9
+ def call(env)
10
+ request_path = env["PATH_INFO"]
11
+ if request_path.start_with?(@url_prefix)
12
+ file_path = request_path[@url_prefix.length..-1]
13
+ env["PATH_INFO"] = file_path
14
+ @file_server.call(env)
15
+ else
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # Note that all components in base_controller/*.rb are loaded automatically, from
2
+ # config/routes.rb, **after** this file is loaded. See the end of this file.
3
+
4
+ require "sinatra/base"
5
+
6
+ class Simple::Httpd::BaseController < Sinatra::Base
7
+ set :logging, true
8
+
9
+ # --- Sinatra::Reloader -----------------------------------------------------
10
+
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
17
+ end
18
+ end
19
+
20
+ Dir.chdir __dir__ do
21
+ Dir.glob("base_controller/*.rb").sort.each do |file|
22
+ require_relative file
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ require "cgi"
2
+
3
+ class Simple::Httpd::BaseController
4
+ helpers do
5
+ def base_url
6
+ @base_url ||= request.base_url
7
+ end
8
+
9
+ def full_url(path, opts = {})
10
+ build_url(base_url, path, opts)
11
+ end
12
+
13
+ def url(path, opts = {})
14
+ build_url(path, opts)
15
+ end
16
+
17
+ def build_url(base, *args)
18
+ option_args, string_args = args.partition { |arg| arg.is_a?(Hash) }
19
+ options = option_args.inject({}) { |hsh, option| hsh.update option }
20
+
21
+ url = File.join([base] + string_args)
22
+
23
+ query = build_url_query(options)
24
+ url += url.index("?") ? "&#{query}" : "?#{query}" if query
25
+ url
26
+ end
27
+
28
+ private
29
+
30
+ def build_url_query(params)
31
+ params = params.reject { |_k, v| v.nil? || v.empty? }
32
+ return nil if params.empty?
33
+
34
+ params.map { |k, value| "#{k}=#{escape(value.to_s)}" }.join("&")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
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
+ }
13
+
14
+ options "*" do
15
+ 200
16
+ end
17
+
18
+ after do
19
+ headers CORS_HEADERS
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ class Simple::Httpd::BaseController
2
+ helpers do
3
+ def debug(data)
4
+ content_type "text/plain"
5
+ halt data.pretty_inspect
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ require "erb"
2
+
3
+ class Simple::Httpd::BaseController
4
+ # A simple ERB renderer
5
+ helpers do
6
+ module ERB::Helpers
7
+ def self.json(data)
8
+ JSON.pretty_generate(data)
9
+ end
10
+ end
11
+
12
+ def erb(template, data)
13
+ content_type "text/html"
14
+
15
+ erb = template.is_a?(ERB) ? template : ERB.new(template)
16
+ data[:helpers] = ERB::Helpers
17
+ erb.result_with_hash(data)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,147 @@
1
+ require_relative "./json"
2
+
3
+ class Simple::Httpd::BaseController
4
+ set :show_exceptions, false
5
+ set :dump_errors, false
6
+ set :raise_errors, false
7
+
8
+ set :raise_errors, true if ENV["RACK_ENV"] == "test"
9
+
10
+ private
11
+
12
+ def stringify_hash(hsh)
13
+ return unless hsh
14
+
15
+ hsh.inject({}) do |r, (k, v)|
16
+ k = k.to_s if k.is_a?(Symbol)
17
+ r.update k => v
18
+ end
19
+ end
20
+
21
+ public
22
+
23
+ def render_error(exc, options)
24
+ expect! options => {
25
+ status: Integer,
26
+ title: String,
27
+ description: [String, nil]
28
+ }
29
+
30
+ status options[:status]
31
+
32
+ options = stringify_hash(options)
33
+ options["description"] ||= options["title"]
34
+ options["@type"] = error_type(exc)
35
+ options["@now"] = Time.now.to_f
36
+
37
+ json options
38
+ end
39
+
40
+ if defined?(Expectation)
41
+
42
+ error(Expectation::Matcher::Mismatch) do |exc|
43
+ render_error exc, status: 400,
44
+ title: "Invalid input",
45
+ description: error_description(exc)
46
+ end
47
+
48
+ end
49
+
50
+ # class InvalidRequest < RuntimeError
51
+ # end
52
+ #
53
+ # error(InvalidRequest) do |e|
54
+ # render_error e, status: 400,
55
+ # title: "Invalid input",
56
+ # description: error_description(e)
57
+ # end
58
+
59
+ error(ArgumentError) do |exc|
60
+ STDERR.puts "Caught ArgumentError: #{exc}, from\n\t#{exc.backtrace[0, 5].join("\n\t")}"
61
+
62
+ render_error exc, status: 422,
63
+ title: "Invalid input #{exc.inspect}",
64
+ description: error_description(exc)
65
+ end
66
+
67
+ # class NotAuthorizedError < RuntimeError
68
+ # end
69
+ #
70
+ # error(NotAuthorizedError) do
71
+ # render_error e, status: 403,
72
+ # title: "Not authorized",
73
+ # description: "You don't have necessary powers to access this page."
74
+ # end
75
+
76
+ # class LoginRequiredError < RuntimeError
77
+ # end
78
+ #
79
+ # error(LoginRequiredError) do
80
+ # render_error e, status: 404,
81
+ # title: "Not found",
82
+ # description: "The server failed to recognize affiliation. Please provide a valid Session-Id."
83
+ # end
84
+
85
+ class NotFoundError < RuntimeError
86
+ end
87
+
88
+ error(NotFoundError) do |exc|
89
+ render_error exc, status: 404,
90
+ title: "Not found",
91
+ description: error_description(exc)
92
+ end
93
+
94
+ error(Errno::ENOENT) do |exc|
95
+ render_error exc, status: 404,
96
+ title: "Not found",
97
+ description: "The requested record was not found."
98
+ end
99
+
100
+ # -- print unspecified errors.
101
+
102
+ error do |exc|
103
+ message = <<~MSG
104
+ === #{exc.class.name} =====================
105
+ #{exc.message.chomp}
106
+
107
+ #{filtered_backtrace(exc)}
108
+ ==================================================================
109
+ MSG
110
+
111
+ STDERR.puts message
112
+ status 500
113
+ "\n#{message}\n"
114
+ end
115
+
116
+ private
117
+
118
+ def error_type(exc)
119
+ "error/#{exc.class.name.underscore}".gsub(/\/error$/, "")
120
+ end
121
+
122
+ def error_description(exc)
123
+ exc.message
124
+ # "#{exc.message}, from #{exc.backtrace.join("\n\t")}"
125
+ end
126
+
127
+ def remove_wd(str)
128
+ @wd ||= Dir.getwd
129
+
130
+ if str.start_with?(@wd)
131
+ str[(@wd.length + 1)..-1]
132
+ else
133
+ str
134
+ end
135
+ end
136
+
137
+ def filtered_backtrace(exc, count: 20)
138
+ lines = exc.backtrace.map do |line|
139
+ next "...\n" if line =~ /\.rvm\b/
140
+
141
+ "#{remove_wd(line)}\n"
142
+ end
143
+
144
+ s = lines[0, count].join("")
145
+ s.gsub(/(\.\.\.\n)+/, " ... (lines removed) ...\n")
146
+ end
147
+ end
@@ -0,0 +1,46 @@
1
+ class Simple::Httpd::BaseController
2
+ def json(result)
3
+ content_type :json
4
+ generate_json(result)
5
+ end
6
+
7
+ private
8
+
9
+ def generate_json(result)
10
+ JSON.generate(result)
11
+ end
12
+
13
+ configure :development, :test do
14
+ begin
15
+ @@neatjson = true
16
+ require "neatjson"
17
+ rescue LoadError
18
+ @@neatjson = false
19
+ end
20
+
21
+ 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_json_body
33
+ @parsed_json_body ||= parse_json_body
34
+ end
35
+
36
+ private
37
+
38
+ def parse_json_body
39
+ unless request.content_type =~ /application\/json/
40
+ raise "Cannot parse non-JSON request body w/content_type #{request.content_type.inspect}"
41
+ end
42
+
43
+ request.body.rewind
44
+ JSON.parse(request.body.read)
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ # Simple::SQL connection handling
2
+ class Simple::Httpd::BaseController
3
+ before do
4
+ @processing_started_at = Time.now
5
+ end
6
+
7
+ after do
8
+ runtime = Time.now - @processing_started_at
9
+ headers "X-Processing" => runtime.to_s
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Simple::Httpd
2
+ module GemHelper
3
+ extend self
4
+
5
+ def version(name)
6
+ spec = Gem.loaded_specs[name]
7
+ version = spec ? spec.version.to_s : "0.0.0"
8
+ version += "+unreleased" if !spec || unreleased?(spec)
9
+ version
10
+ end
11
+
12
+ private
13
+
14
+ def unreleased?(spec)
15
+ return false unless defined?(Bundler::Source::Gemspec)
16
+ return true if spec.source.is_a?(::Bundler::Source::Gemspec)
17
+ return true if spec.source.is_a?(::Bundler::Source::Path)
18
+
19
+ false
20
+ end
21
+ end
22
+
23
+ VERSION = GemHelper.version "postjob"
24
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ cloc $(find lib/ -name *rb) | grep -E 'Language|Ruby' | sed 's-Language- -'
4
+ printf "\n"
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ watchr lib,spec rspec $@
@@ -0,0 +1,41 @@
1
+ # This file is part of the sinatra-sse ruby gem.
2
+ #
3
+ # Copyright (c) 2016, 2017 @radiospiel, mediapeers Gem
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ lib = File.expand_path('../lib', __FILE__)
7
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.name = "simple-httpd"
11
+ gem.version = File.read("VERSION")
12
+
13
+ gem.authors = [ "radiospiel" ]
14
+ gem.email = "eno@radiospiel.org"
15
+ gem.homepage = "http://github.com/radiospiel/simple-httpd"
16
+ gem.summary = "Super-simple HTTPD server"
17
+
18
+ gem.description = "Super-simple HTTPD server - sinatra w/gimmiks"
19
+
20
+ gem.files = `git ls-files`.split($/)
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = %w(lib)
23
+
24
+ # executables are used for development purposes only
25
+ gem.executables = []
26
+
27
+ gem.required_ruby_version = '~> 2.5'
28
+
29
+ # -- dependencies for postjob httpd
30
+ gem.add_runtime_dependency "neatjson", "~> 0.8.4"
31
+ gem.add_runtime_dependency "sinatra", "~> 2"
32
+ gem.add_runtime_dependency "sinatra-reloader", "~> 1"
33
+
34
+ # development gems
35
+ gem.add_development_dependency "rspec-httpd", "~> 0.0.14"
36
+ gem.add_development_dependency 'rake', '~> 11'
37
+ gem.add_development_dependency 'rspec', '~> 3.7'
38
+ gem.add_development_dependency 'rubocop', '~> 0.61.1'
39
+ gem.add_development_dependency 'simplecov', '~> 0'
40
+ gem.add_development_dependency 'awesome_print', '~> 0'
41
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Httpd do
4
+ describe "VERSION" do
5
+ it "defines a version string" do
6
+ # Note: this allows for 0.12.34beta
7
+ #expect(Simple::Httpd::VERSION).to match(/^\d+\.\d+\.\d+/)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ %w(auth authentication authorization).each do |library_name|
2
+ path = File.expand_path("../../#{library_name}/lib", __FILE__)
3
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
4
+ end
5
+
6
+ ENV["RACK_ENV"] = "test"
7
+ ENV["RAILS_ENV"] = "test"
8
+
9
+ require "byebug"
10
+ require "rspec"
11
+ require "awesome_print"
12
+ Dir.glob("./spec/support/**/*.rb").sort.each { |path| load path }
13
+
14
+ require "simple/httpd"
15
+
16
+ RSpec.configure do |config|
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run focus: (ENV["CI"] != "true")
19
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
20
+ config.order = "random"
21
+ config.example_status_persistence_file_path = ".rspec.data"
22
+
23
+ config.backtrace_exclusion_patterns << /spec\/support/
24
+ config.backtrace_exclusion_patterns << /spec_helper/
25
+ config.backtrace_exclusion_patterns << /database_cleaner/
26
+
27
+ # config.around(:each) do |example|
28
+ # example.run
29
+ # end
30
+ end
@@ -0,0 +1,22 @@
1
+ require "simplecov"
2
+
3
+ # make sure multiple runs result in multiple result set. SimpleCov will take
4
+ # care of merging these results automatically.
5
+ SimpleCov.command_name "test:#{ENV['USE_ACTIVE_RECORD']}"
6
+
7
+ USE_ACTIVE_RECORD = ENV["USE_ACTIVE_RECORD"] == "1"
8
+
9
+ SimpleCov.start do
10
+ # return true to remove src from coverage
11
+ add_filter do |src|
12
+ next true if src.filename =~ /\/spec\//
13
+ next true if src.filename =~ /\/immutable\.rb/
14
+
15
+ next true if USE_ACTIVE_RECORD && src.filename =~ /\/sql\/connection\/raw_connection\.rb/
16
+ next true if !USE_ACTIVE_RECORD && src.filename =~ /\/sql\/connection\/active_record_connection\.rb/
17
+
18
+ false
19
+ end
20
+
21
+ minimum_coverage 90
22
+ end
@@ -0,0 +1,104 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ GEM_ROOT = File.expand_path('../../', __FILE__)
5
+ GEM_SPEC, more = Dir.glob("*.gemspec")
6
+ raise "Cannot determine gemspec" if more || !GEM_SPEC
7
+
8
+ VERSION_FILE_PATH = 'VERSION'
9
+
10
+ class VersionNumberTracker
11
+ class << self
12
+ def update_version_file(new_version_number)
13
+ File.open(VERSION_FILE_PATH, 'w') { |file| file.puts new_version_number }
14
+ new_version_number
15
+ end
16
+
17
+ def auto_version_bump
18
+ old_version_number = File.read("VERSION")
19
+ old = old_version_number.split('.')
20
+ current = old[0..-2] << old[-1].next
21
+ new_version_number = current.join('.')
22
+
23
+ update_version_file(new_version_number)
24
+ end
25
+
26
+ def manual_version_bump
27
+ update_version_file(ENV['VERSION'])
28
+ end
29
+
30
+ def update_version_number
31
+ @version = ENV['VERSION'] ? manual_version_bump : auto_version_bump
32
+ end
33
+
34
+ attr_reader :version
35
+ end
36
+ end
37
+
38
+ namespace :release do
39
+ task :version do
40
+ VersionNumberTracker.update_version_number
41
+ end
42
+
43
+ task :build do
44
+ Dir.chdir(GEM_ROOT) do
45
+ sh("gem build #{GEM_SPEC}")
46
+ end
47
+ end
48
+
49
+ desc "Commit changes"
50
+ task :commit do
51
+ Dir.chdir(GEM_ROOT) do
52
+ version = VersionNumberTracker.version
53
+ sh("git add #{VERSION_FILE_PATH}")
54
+ sh("git commit -m \"bump to v#{version}\"")
55
+ sh("git tag -a v#{version} -m \"Tag\"")
56
+ end
57
+ end
58
+
59
+ desc "Push code and tags"
60
+ task :push do
61
+ sh("git push origin #{$TARGET_BRANCH}")
62
+ sh('git push --tags')
63
+ end
64
+
65
+ desc "Cleanup"
66
+ task :clean do
67
+ Dir.glob(File.join(GEM_ROOT, '*.gem')).each { |f| FileUtils.rm_rf(f) }
68
+ end
69
+
70
+ desc "Push Gem to gemfury"
71
+ task :publish do
72
+ Dir.chdir(GEM_ROOT) { sh("gem push #{Dir.glob('*.gem').first}") }
73
+ end
74
+
75
+ task :target_master do
76
+ $TARGET_BRANCH = 'master'
77
+ end
78
+
79
+ task :target_stable do
80
+ $TARGET_BRANCH = 'stable'
81
+ end
82
+
83
+ task :checkout do
84
+ sh "git status --untracked-files=no --porcelain > /dev/null || (echo '*** working dir not clean' && false)"
85
+ sh "git checkout #{$TARGET_BRANCH}"
86
+ sh "git pull"
87
+ end
88
+
89
+ task default: [
90
+ 'checkout',
91
+ 'version',
92
+ 'clean',
93
+ 'build',
94
+ 'commit',
95
+ 'push',
96
+ 'publish'
97
+ ]
98
+
99
+ task master: %w(target_master default)
100
+ task stable: %w(target_stable default)
101
+ end
102
+
103
+ desc "Clean, build, commit and push"
104
+ task release: 'release:master'
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-httpd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - radiospiel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: neatjson
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra-reloader
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-httpd
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.14
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.14
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.61.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.61.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: awesome_print
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Super-simple HTTPD server - sinatra w/gimmiks
140
+ email: eno@radiospiel.org
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - ".gitignore"
146
+ - ".rubocop.yml"
147
+ - Gemfile
148
+ - README.md
149
+ - Rakefile
150
+ - VERSION
151
+ - bin/bundle
152
+ - bin/console
153
+ - bin/rake
154
+ - bin/rspec
155
+ - bin/rubocop
156
+ - lib/simple-httpd.rb
157
+ - lib/simple.rb
158
+ - lib/simple/httpd.rb
159
+ - lib/simple/httpd/app.rb
160
+ - lib/simple/httpd/app/file_server.rb
161
+ - lib/simple/httpd/base_controller.rb
162
+ - lib/simple/httpd/base_controller/build_url.rb
163
+ - lib/simple/httpd/base_controller/cors.rb
164
+ - lib/simple/httpd/base_controller/debug.rb
165
+ - lib/simple/httpd/base_controller/erb.rb
166
+ - lib/simple/httpd/base_controller/error_handling.rb
167
+ - lib/simple/httpd/base_controller/json.rb
168
+ - lib/simple/httpd/base_controller/x_processing.rb
169
+ - lib/simple/httpd/version.rb
170
+ - log/.gitkeep
171
+ - scripts/stats
172
+ - scripts/watch
173
+ - simple-httpd.gemspec
174
+ - spec/simple/httpd/version_spec.rb
175
+ - spec/spec_helper.rb
176
+ - spec/support/004_simplecov.rb
177
+ - tasks/release.rake
178
+ homepage: http://github.com/radiospiel/simple-httpd
179
+ licenses: []
180
+ metadata: {}
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '2.5'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubyforge_project:
197
+ rubygems_version: 2.7.6
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: Super-simple HTTPD server
201
+ test_files:
202
+ - spec/simple/httpd/version_spec.rb
203
+ - spec/spec_helper.rb
204
+ - spec/support/004_simplecov.rb