cargobull 0.2.1 → 0.3.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 +7 -0
- data/LICENSE.md +1 -1
- data/lib/cargobull.rb +13 -0
- data/lib/cargobull/dispatch.rb +35 -32
- data/lib/cargobull/env.rb +23 -19
- data/lib/cargobull/extensions/string.rb +13 -6
- data/lib/cargobull/initialize.rb +19 -15
- data/lib/cargobull/rackup.rb +32 -29
- data/lib/cargobull/service.rb +5 -9
- data/lib/cargobull/test_helper.rb +4 -26
- metadata +12 -14
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 868c60b92a3cf7f1763e57529d5d504c2f32a3a4
|
4
|
+
data.tar.gz: 1d6a799fdf3b5832eee6c2f4a981ac1c3325fcfa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 391caf4e77d14fab93440ee642eb2beec5dc568c739a7d267eb707befa344c9712c5088db13ad3491bbff41ba2a4b30a26f523e934fea23206501801a97d5a41
|
7
|
+
data.tar.gz: 1edbfe36a522992ac5ebc7710dc4b3cef40ffc3438e6fa2245b8703b36cae8a1a77e9731876056b59846693d695ab00f7e78b990556184b60be9f9ecd79f8fa6
|
data/LICENSE.md
CHANGED
data/lib/cargobull.rb
CHANGED
@@ -4,6 +4,19 @@ require 'cargobull/service'
|
|
4
4
|
require 'cargobull/dispatch'
|
5
5
|
require 'cargobull/rackup'
|
6
6
|
|
7
|
+
module Cargobull
|
8
|
+
def self.runner(cargoenv=env.get)
|
9
|
+
->(env) do
|
10
|
+
cenv = cargoenv.dup
|
11
|
+
cenv[:rackenv] = env
|
12
|
+
cenv[:request_path] = env["REQUEST_PATH"]
|
13
|
+
cenv[:request_method] = env["REQUEST_METHOD"]
|
14
|
+
cenv.freeze
|
15
|
+
Rackup.call(cenv)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
if File.exist?('./setup.rb')
|
8
21
|
require 'cargobull/initialize'
|
9
22
|
require './setup'
|
data/lib/cargobull/dispatch.rb
CHANGED
@@ -1,47 +1,50 @@
|
|
1
1
|
|
2
2
|
module Cargobull
|
3
3
|
module Dispatch
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
4
|
+
METHOD_MAP = {
|
5
|
+
"GET" => :read,
|
6
|
+
"POST" => :create,
|
7
|
+
"PATCH" => :update,
|
8
|
+
"PUT" => :update,
|
9
|
+
"DELETE" => :delete
|
10
|
+
}
|
11
|
+
|
12
|
+
def self.translate_method_call(env, method)
|
13
|
+
METHOD_MAP[method.to_s] ||
|
14
|
+
[405, { "Content-Type" => env[:ctype] }, env[:e405] ]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.translate_action_call(env, action)
|
18
|
+
Service.dispatch_to(action) ||
|
19
|
+
[404, { "Content-Type" => env[:ctype] }, env[:e404] ]
|
17
20
|
end
|
18
21
|
|
19
|
-
def self.
|
20
|
-
|
21
|
-
|
22
|
-
raise RuntimeError.new("Unsupported action: #{action}")
|
23
|
-
end
|
24
|
-
return klass
|
22
|
+
def self.call(env, method, action, *params)
|
23
|
+
dispatch(env, env[:transform_in], env[:transform_out], method, action,
|
24
|
+
*params)
|
25
25
|
end
|
26
26
|
|
27
|
-
def self.
|
28
|
-
klass =
|
27
|
+
def self.dispatch(env, tfin, tfout, method, action, *params)
|
28
|
+
klass = translate_action_call(env, action)
|
29
|
+
return klass if klass.is_a?(Array) # break on error
|
30
|
+
klass = klass.constantize
|
31
|
+
|
32
|
+
method = translate_method_call(env, method)
|
33
|
+
return method if method.is_a?(Array) # break on error
|
29
34
|
|
30
|
-
|
31
|
-
args = [blk.call(*args)] if blk
|
35
|
+
params = tfin.call(*params) if tfin
|
32
36
|
|
33
|
-
obj = klass.
|
34
|
-
method = self.translate_method_call(method)
|
35
|
-
unless obj.respond_to?(method)
|
36
|
-
raise RuntimeError.new("#{action} does not respond to #{method}")
|
37
|
-
end
|
37
|
+
obj = klass.is_a?(Class) ? klass.new : klass
|
38
38
|
|
39
|
-
return
|
39
|
+
return obj.respond_to?(method) ?
|
40
|
+
transform(env, obj.send(method, *params), &tfout) :
|
41
|
+
[404, { "Content-Type" => env[:ctype] }, env[:e404]]
|
40
42
|
end
|
41
43
|
|
42
|
-
def self.transform(data)
|
43
|
-
|
44
|
-
return
|
44
|
+
def self.transform(env, data)
|
45
|
+
data = yield(data) if block_given?
|
46
|
+
return data.is_a?(Array) && data.count == 3 ? data :
|
47
|
+
[200, { "Content-Type" => env[:ctype] }, data]
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
data/lib/cargobull/env.rb
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
|
2
2
|
module Cargobull
|
3
3
|
def self.env
|
4
|
-
|
4
|
+
Env
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
module Env
|
8
|
+
DEFAULTS = {
|
9
|
+
dispatch_url: "/api",
|
10
|
+
file_url: "/",
|
11
|
+
default_files: ["index.html", "index.htm"],
|
12
|
+
default_path: nil,
|
13
|
+
ctype: "text/plain",
|
14
|
+
e403: "Forbidden",
|
15
|
+
e404: "Not found",
|
16
|
+
e405: "Method not allowed",
|
17
|
+
e500: "Internal error",
|
18
|
+
transform_out: nil,
|
19
|
+
transform_in: nil
|
20
|
+
}
|
16
21
|
|
17
|
-
def self.
|
18
|
-
|
19
|
-
@dispatch_url = sanitized_url ? "/#{sanitized_url}" : "/"
|
20
|
-
@serve_url = sanitized_url ? "/" : "/files"
|
22
|
+
def self.get(*args)
|
23
|
+
update(DEFAULTS.dup, *args)
|
21
24
|
end
|
22
25
|
|
23
|
-
def self.
|
24
|
-
|
25
|
-
|
26
|
+
def self.update(env, *args)
|
27
|
+
(args.first.is_a?(Hash) ? args.first : Hash[*args]).reduce(env) do
|
28
|
+
|acc, (k, v)|
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
acc[k.to_sym] = respond_to?(k) ? send(k, v) : v
|
31
|
+
next acc
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -33,24 +33,31 @@
|
|
33
33
|
#
|
34
34
|
class String
|
35
35
|
def constantize
|
36
|
-
|
36
|
+
split('::').reduce(Module){ |m, c| m.const_get(c) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def path_to_modules
|
40
|
+
split(/\//).map(&:capitalize).join('::')
|
41
|
+
end
|
42
|
+
|
43
|
+
def modules_to_path
|
44
|
+
sub(/:+/, '/')
|
37
45
|
end
|
38
46
|
|
39
47
|
def camelize
|
40
|
-
|
41
|
-
split(/\//).map(&:capitalize).join('::')
|
48
|
+
split(/_/).map(&:capitalize).join.path_to_modules
|
42
49
|
end
|
43
50
|
|
44
51
|
def camelize!
|
45
|
-
|
52
|
+
replace(camelize)
|
46
53
|
end
|
47
54
|
|
48
55
|
def underscore
|
49
|
-
|
56
|
+
modules_to_path.split(/([A-Z]?[^A-Z]*)/).reject(&:empty?).
|
50
57
|
map(&:downcase).join('_').gsub(/\/_/, '/')
|
51
58
|
end
|
52
59
|
|
53
60
|
def underscore!
|
54
|
-
|
61
|
+
replace(underscore)
|
55
62
|
end
|
56
63
|
end
|
data/lib/cargobull/initialize.rb
CHANGED
@@ -4,7 +4,7 @@ module Cargobull
|
|
4
4
|
@file_map = []
|
5
5
|
|
6
6
|
def self.sanitize_file_name(file_name)
|
7
|
-
|
7
|
+
"./#{File.basename(file_name)}"
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.dir(*args)
|
@@ -13,18 +13,9 @@ module Cargobull
|
|
13
13
|
|
14
14
|
sanitized_args.each do |dir|
|
15
15
|
ruby_files = Dir["#{dir}/**/*.rb"]
|
16
|
-
@file_map = ruby_files.
|
17
|
-
|
18
|
-
|
19
|
-
mod = mods.reduce(Object) do |acc, mod_str|
|
20
|
-
unless acc.const_defined?(mod_str)
|
21
|
-
acc.const_set(mod_str, Module.new)
|
22
|
-
end
|
23
|
-
next acc.const_get(mod_str)
|
24
|
-
end
|
25
|
-
|
26
|
-
mod.autoload(klass_name, f)
|
27
|
-
acc << f
|
16
|
+
@file_map = ruby_files.each do |f|
|
17
|
+
full_klass = f.sub(/^#{dir}\/?/, '').sub(/\.rb$/, '').camelize
|
18
|
+
register_file(full_klass, f)
|
28
19
|
end
|
29
20
|
end
|
30
21
|
end
|
@@ -32,8 +23,21 @@ module Cargobull
|
|
32
23
|
def self.file(klass_str, file_name)
|
33
24
|
file_name = sanitize_file_name(file_name)
|
34
25
|
return unless File.file?(file_name)
|
35
|
-
|
36
|
-
|
26
|
+
register_file(klass_str, file_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.register_file(full_klass, fname)
|
30
|
+
*mods, klass_name = full_klass.split('::')
|
31
|
+
mod = mods.reduce(Object) do |acc, mod_str|
|
32
|
+
unless acc.const_defined?(mod_str)
|
33
|
+
acc.const_set(mod_str, Module.new)
|
34
|
+
end
|
35
|
+
next acc.const_get(mod_str)
|
36
|
+
end
|
37
|
+
|
38
|
+
mod.autoload(klass_name, fname)
|
39
|
+
@file_map << fname
|
40
|
+
Service.register(full_klass)
|
37
41
|
end
|
38
42
|
|
39
43
|
def self.init_all
|
data/lib/cargobull/rackup.rb
CHANGED
@@ -1,50 +1,53 @@
|
|
1
1
|
|
2
2
|
module Cargobull
|
3
|
-
|
4
|
-
def file(env)
|
5
|
-
path = env[
|
6
|
-
|
7
|
-
path.sub!(/^#{Cargobull.env.serve_url}\/?/i, '')
|
3
|
+
module Rackup
|
4
|
+
def self.file(env)
|
5
|
+
path = env[:request_path].gsub(/\/\.+/, '').
|
6
|
+
sub(/^#{env[:serve_url]}\/?/i, '')
|
8
7
|
if path.empty?
|
9
|
-
path =
|
8
|
+
path = env[:default_files].detect do |f|
|
10
9
|
File.file?("./files/#{f}")
|
11
10
|
end
|
12
11
|
end
|
13
12
|
path = "./files/#{path}"
|
14
13
|
if File.file?(path)
|
15
14
|
return [200, {}, File.open(path, File::RDONLY)]
|
16
|
-
elsif
|
17
|
-
return [200, {},
|
18
|
-
File
|
15
|
+
elsif env[:default_path]
|
16
|
+
return [200, {}, File.open("./files/#{env[:default_path]}",
|
17
|
+
File::RDONLY)]
|
19
18
|
else
|
20
|
-
return [404, {},
|
19
|
+
return [404, { "Content-Type" => env[:ctype] }, env[:e404] ]
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
def dispatch(env)
|
25
|
-
req = Rack::Request.new(env)
|
26
|
-
action = env[
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
def self.dispatch(env)
|
24
|
+
req = Rack::Request.new(env[:rackenv])
|
25
|
+
action = env[:request_path].sub(/^#{env[:dispatch_url]}\/?/, '')
|
26
|
+
params = req.GET
|
27
|
+
if req.content_type == "application/x-www-form-urlencoded"
|
28
|
+
params.merge!(req.POST)
|
29
|
+
else
|
30
|
+
params[:body] = req.body
|
31
|
+
end
|
32
|
+
return Dispatch.call(env, env[:request_method], action, params)
|
33
33
|
end
|
34
34
|
|
35
|
-
def self.routes
|
36
|
-
routes = [
|
37
|
-
[/^#{
|
38
|
-
|
39
|
-
]
|
40
|
-
routes.reverse! if Cargobull.env.serve_url == '/'
|
35
|
+
def self.routes(env)
|
36
|
+
routes = [:file, :dispatch].map do |type|
|
37
|
+
[/^#{env["#{type}_url".to_sym]}\/?/i, type]
|
38
|
+
end
|
39
|
+
routes.reverse! if env[:file_url] == '/'
|
41
40
|
return routes.unshift([/^\/favicon/i, :file])
|
42
41
|
end
|
43
42
|
|
44
|
-
def call(env)
|
45
|
-
path = env[
|
46
|
-
_, match_method =
|
47
|
-
|
43
|
+
def self.call(env)
|
44
|
+
path = env[:request_path]
|
45
|
+
_, match_method = routes(env).detect{ |pattern, _| path =~ pattern }
|
46
|
+
if match_method.nil?
|
47
|
+
return [500, { "Content-Type" => env[:ctype] }, env[:e500] ]
|
48
|
+
else
|
49
|
+
return send(match_method, env)
|
50
|
+
end
|
48
51
|
end
|
49
52
|
end
|
50
53
|
end
|
data/lib/cargobull/service.rb
CHANGED
@@ -8,21 +8,17 @@ module Cargobull
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.dispatch_to(action)
|
11
|
-
return
|
12
|
-
next
|
11
|
+
return dispatch.detect do |klass_name|
|
12
|
+
next klass_name.underscore == action.to_s
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.register(
|
17
|
-
@dispatch <<
|
16
|
+
def self.register(klass_name)
|
17
|
+
@dispatch << klass_name unless @dispatch.include?(klass_name)
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.included(base)
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(*args)
|
25
|
-
@params = args.shift || {}
|
21
|
+
register(base.name)
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
@@ -2,33 +2,11 @@ require 'cargobull'
|
|
2
2
|
|
3
3
|
module Cargobull
|
4
4
|
module TestHelper
|
5
|
-
def response
|
6
|
-
return @response || ""
|
7
|
-
end
|
8
|
-
|
9
5
|
[:get, :post, :put, :patch, :delete].each do |m|
|
10
|
-
define_method(m) do |action, *args|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def assert_raise(except_klass)
|
17
|
-
begin
|
18
|
-
yield
|
19
|
-
rescue except_klass
|
20
|
-
assert true
|
21
|
-
return
|
22
|
-
end
|
23
|
-
assert false
|
24
|
-
end
|
25
|
-
|
26
|
-
def assert_nothing_raised
|
27
|
-
begin
|
28
|
-
yield
|
29
|
-
assert true
|
30
|
-
rescue
|
31
|
-
assert false
|
6
|
+
define_method(m) do |env, action, *args, &blk|
|
7
|
+
r = Cargobull::Dispatch.call(env, m.to_s.upcase, action, *args)
|
8
|
+
blk.call(r) if block_given?
|
9
|
+
next r
|
32
10
|
end
|
33
11
|
end
|
34
12
|
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cargobull
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Matthias Geier
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-04-14 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
13
|
description:
|
15
14
|
email:
|
@@ -17,38 +16,37 @@ executables: []
|
|
17
16
|
extensions: []
|
18
17
|
extra_rdoc_files: []
|
19
18
|
files:
|
19
|
+
- LICENSE.md
|
20
20
|
- lib/cargobull.rb
|
21
|
-
- lib/cargobull/service.rb
|
22
|
-
- lib/cargobull/test_helper.rb
|
23
21
|
- lib/cargobull/dispatch.rb
|
24
|
-
- lib/cargobull/initialize.rb
|
25
|
-
- lib/cargobull/rackup.rb
|
26
22
|
- lib/cargobull/env.rb
|
27
23
|
- lib/cargobull/extensions/string.rb
|
28
|
-
-
|
24
|
+
- lib/cargobull/initialize.rb
|
25
|
+
- lib/cargobull/rackup.rb
|
26
|
+
- lib/cargobull/service.rb
|
27
|
+
- lib/cargobull/test_helper.rb
|
29
28
|
homepage: https://github.com/matthias-geier/cargobull
|
30
29
|
licenses:
|
31
30
|
- BSD-2
|
31
|
+
metadata: {}
|
32
32
|
post_install_message:
|
33
33
|
rdoc_options: []
|
34
34
|
require_paths:
|
35
35
|
- lib
|
36
36
|
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
-
none: false
|
38
37
|
requirements:
|
39
|
-
- -
|
38
|
+
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
40
|
version: 2.1.0
|
42
41
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
42
|
requirements:
|
45
|
-
- -
|
43
|
+
- - ">="
|
46
44
|
- !ruby/object:Gem::Version
|
47
45
|
version: '0'
|
48
46
|
requirements: []
|
49
47
|
rubyforge_project:
|
50
|
-
rubygems_version:
|
48
|
+
rubygems_version: 2.4.5.1
|
51
49
|
signing_key:
|
52
|
-
specification_version:
|
50
|
+
specification_version: 4
|
53
51
|
summary: Multipurpose dispatcher for RESTful services
|
54
52
|
test_files: []
|