cargobull 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014, Matthias Geier
1
+ Copyright (c) 2014-2016, Matthias Geier
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
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'
@@ -1,47 +1,50 @@
1
1
 
2
2
  module Cargobull
3
3
  module Dispatch
4
- def self.translate_method_call(method)
5
- return case method.to_s.downcase
6
- when "get", "post"
7
- :read
8
- when "put"
9
- :create
10
- when "patch"
11
- :update
12
- when "delete"
13
- :delete
14
- else
15
- raise RuntimeError.new("Unsupported method: #{method}")
16
- end
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.translate_action_call(action)
20
- klass = Service.dispatch_to(action)
21
- if klass.nil?
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.call(method, action, *args)
28
- klass = self.translate_action_call(action)
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
- blk = Cargobull.env.transform_in
31
- args = [blk.call(*args)] if blk
35
+ params = tfin.call(*params) if tfin
32
36
 
33
- obj = klass.new(*args)
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 self.transform(obj.send(method))
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
- blk = Cargobull.env.transform_out
44
- return blk ? blk.call(data) : data
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
- return Env
4
+ Env
5
5
  end
6
6
 
7
- class Env
8
- class << self
9
- attr_reader :dispatch_url, :serve_url, :transform_out, :transform_in
10
- attr_accessor :default_files, :default_path
11
- end
12
-
13
- @dispatch_url = "/"
14
- @serve_url = "/files"
15
- @default_files = ['index.html', 'index.htm']
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.dispatch_url=(url)
18
- sanitized_url = (url || "").split('/').reject(&:empty?).first
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.transform_out=(blk)
24
- @transform_out = blk
25
- end
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
- def self.transform_in=(blk)
28
- @transform_in = blk
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
- return self.to_s.split('::').reduce(Module){ |m, c| m.const_get(c) }
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
- return self.to_s.split(/_/).map(&:capitalize).join.
41
- split(/\//).map(&:capitalize).join('::')
48
+ split(/_/).map(&:capitalize).join.path_to_modules
42
49
  end
43
50
 
44
51
  def camelize!
45
- self.replace(self.to_s.camelize)
52
+ replace(camelize)
46
53
  end
47
54
 
48
55
  def underscore
49
- return self.to_s.sub(/:+/, '/').split(/([A-Z]?[^A-Z]*)/).reject(&:empty?).
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
- self.replace(self.to_s.underscore)
61
+ replace(underscore)
55
62
  end
56
63
  end
@@ -4,7 +4,7 @@ module Cargobull
4
4
  @file_map = []
5
5
 
6
6
  def self.sanitize_file_name(file_name)
7
- return "./#{File.basename(file_name)}"
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.reduce(@file_map) do |acc, f|
17
- file_name = f.sub(/^#{dir}\/?/, '').sub(/\.rb$/, '').camelize
18
- *mods, klass_name = file_name.split('::')
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
- Object.autoload(klass_str, file_name)
36
- @file_map << file_name
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
@@ -1,50 +1,53 @@
1
1
 
2
2
  module Cargobull
3
- class Rackup
4
- def file(env)
5
- path = env["REQUEST_PATH"]
6
- path.gsub!(/\/\.+/, '')
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 = Cargobull.env.default_files.detect do |f|
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 Cargobull.env.default_path
17
- return [200, {},
18
- File.open("./files/#{Cargobull.env.default_path}", File::RDONLY)]
15
+ elsif env[:default_path]
16
+ return [200, {}, File.open("./files/#{env[:default_path]}",
17
+ File::RDONLY)]
19
18
  else
20
- return [404, {}, "Not found"]
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["REQUEST_PATH"].sub(/^#{Cargobull.env.dispatch_url}\/?/, '').
27
- gsub(/\/[^\/]+/, '')
28
- params = req.POST.merge(req.GET)
29
- data = Cargobull::Dispatch.call(env["REQUEST_METHOD"], action, params)
30
- return [200, {}, data]
31
- rescue RuntimeError
32
- return [404, {}, "Not found"]
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
- [/^#{Cargobull.env.serve_url}\/?/i, :file],
38
- [/^#{Cargobull.env.dispatch_url}\/?/i, :dispatch]
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["REQUEST_PATH"]
46
- _, match_method = self.class.routes.detect{ |pattern, _| path =~ pattern }
47
- return self.send(match_method, env)
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
@@ -8,21 +8,17 @@ module Cargobull
8
8
  end
9
9
 
10
10
  def self.dispatch_to(action)
11
- return self.dispatch.detect do |klass|
12
- next klass.name.underscore == action.to_s
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(klass)
17
- @dispatch << klass
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
- self.register base
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
- @response = nil
12
- @response = Cargobull::Dispatch.call(m, action, *args)
13
- end
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.2.1
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: 2014-09-28 00:00:00.000000000 Z
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
- - LICENSE.md
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: 1.8.23
48
+ rubygems_version: 2.4.5.1
51
49
  signing_key:
52
- specification_version: 3
50
+ specification_version: 4
53
51
  summary: Multipurpose dispatcher for RESTful services
54
52
  test_files: []