cargobull 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8afc99ac65f76c719411449cec7fffb3117f2c80
4
+ data.tar.gz: fd4ad2a39ecd949df7233668ddd57b435f7cefe2
5
+ SHA512:
6
+ metadata.gz: 5396ab2ec3a1ce7e4966bcad1320e49f48fbef53923d033a0806b5fc5f041aa6ab23840b37410406d02eb909b7c4d7bd5af3723389f749943deefb970d3e9d6d
7
+ data.tar.gz: 0571ae1fa809f89bc63f0e9dbce8bcd520253cd628202d6e77bca0752768fa54054c58e08142729665cdf2eb75a4d7089b3f08cc5f8cf9c66a073f947cb2c895
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2014, Matthias Geier
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,11 @@
1
+ require 'cargobull/extensions/string'
2
+ require 'cargobull/env'
3
+ require 'cargobull/service'
4
+ require 'cargobull/dispatch'
5
+ require 'cargobull/rackup'
6
+
7
+ if File.exist?('./setup.rb')
8
+ require 'cargobull/initialize'
9
+ require './setup'
10
+ Cargobull::Initialize.init_all
11
+ end
@@ -0,0 +1,47 @@
1
+
2
+ module Cargobull
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
17
+ end
18
+
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
25
+ end
26
+
27
+ def self.call(method, action, *args)
28
+ klass = self.translate_action_call(action)
29
+
30
+ blk = Cargobull.env.transform_in
31
+ args = [blk.call(*args)] if blk
32
+
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
38
+
39
+ return self.transform(obj.send(method))
40
+ end
41
+
42
+ def self.transform(data)
43
+ blk = Cargobull.env.transform_out
44
+ return blk ? blk.call(data) : data
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module Cargobull
3
+ def self.env
4
+ return Env
5
+ end
6
+
7
+ class Env
8
+ class << self
9
+ attr_reader :dispatch_url, :serve_url, :transform_out, :transform_in
10
+ attr_accessor :default_files
11
+ end
12
+
13
+ @dispatch_url = "/"
14
+ @serve_url = "/files"
15
+ @default_files = ['index.html', 'index.htm']
16
+
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"
21
+ end
22
+
23
+ def self.transform_out=(blk)
24
+ @transform_out = blk
25
+ end
26
+
27
+ def self.transform_in=(blk)
28
+ @transform_in = blk
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ # = String class extension
2
+ #
3
+ # A string that is supposed to becode a Module, Class or similar can be
4
+ # transformed by using #constantize
5
+ #
6
+ # "Array".constantize
7
+ # => Array
8
+ #
9
+ # When writing file names in ruby, they are usually an underscore (snakecase)
10
+ # representation of the class name. It can be transformed with #camelize and
11
+ # in place with #camelize!
12
+ #
13
+ # "file_reader".camelize
14
+ # => "FileReader"
15
+ #
16
+ # s = "file_reader"
17
+ # s.camelize!
18
+ # s
19
+ # => "FileReader"
20
+ #
21
+ # The backwards transformation from a class name to snakecase is done with
22
+ # #underscore and in place with #underscore!
23
+ #
24
+ # "FileReader".underscore
25
+ # => "file_reader"
26
+ #
27
+ # s = "FileReader".underscore
28
+ # s.underscore!
29
+ # s
30
+ # => "file_reader"
31
+ #
32
+ #
33
+ #
34
+ class String
35
+ def constantize
36
+ return self.to_s.split('::').reduce(Module){ |m, c| m.const_get(c) }
37
+ end
38
+
39
+ def camelize
40
+ return self.to_s.split(/_/).map(&:capitalize).join
41
+ end
42
+
43
+ def camelize!
44
+ self.replace(self.to_s.camelize)
45
+ end
46
+
47
+ def underscore
48
+ return self.to_s.split(/([A-Z]?[^A-Z]*)/).reject(&:empty?).
49
+ map(&:downcase).join('_')
50
+ end
51
+
52
+ def underscore!
53
+ self.replace(self.to_s.underscore)
54
+ end
55
+ end
@@ -0,0 +1,35 @@
1
+
2
+ module Cargobull
3
+ module Initialize
4
+ @file_map = []
5
+
6
+ def self.sanitize_file_name(file_name)
7
+ return "./#{File.basename(file_name)}"
8
+ end
9
+
10
+ def self.dir(*args)
11
+ sanitized_args = args.map{ |d| sanitize_file_name(d).sub(/\/$/, '') }.
12
+ select{ |d| File.directory?(d) }
13
+
14
+ sanitized_args.each do |dir|
15
+ ruby_files = Dir["#{dir}/*.rb"]
16
+ @file_map = ruby_files.reduce(@file_map) do |acc, f|
17
+ file_name = File.basename(f).sub(/\.rb$/, '')
18
+ Object.autoload(file_name.camelize, f)
19
+ acc << f
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.file(klass_str, file_name)
25
+ file_name = sanitize_file_name(file_name)
26
+ return unless File.file?(file_name)
27
+ Object.autoload(klass_str, file_name)
28
+ @file_map << file_name
29
+ end
30
+
31
+ def self.init_all
32
+ @file_map.each{ |file| require file }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+
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, '')
8
+ if path.empty?
9
+ path = Cargobull.env.default_files.detect do |f|
10
+ File.file?("./files/#{f}")
11
+ end
12
+ end
13
+ path = "./files/#{path}"
14
+ if File.file?(path)
15
+ return [200, {}, File.open(path, File::RDONLY)]
16
+ else
17
+ return [404, {}, "Not found"]
18
+ end
19
+ end
20
+
21
+ def dispatch(env)
22
+ req = Rack::Request.new(env)
23
+ action = env["REQUEST_PATH"].sub(/^#{Cargobull.env.dispatch_url}\/?/, '').
24
+ gsub(/\/[^\/]+/, '')
25
+ params = req.POST.merge(req.GET)
26
+ data = Cargobull::Dispatch.call(env["REQUEST_METHOD"], action, params)
27
+ return [200, {}, data]
28
+ rescue RuntimeError
29
+ return [404, {}, "Not found"]
30
+ end
31
+
32
+ def self.routes
33
+ routes = [
34
+ [/^#{Cargobull.env.serve_url}\/?/i, :file],
35
+ [/^#{Cargobull.env.dispatch_url}\/?/i, :dispatch]
36
+ ]
37
+ routes.reverse! if Cargobull.env.serve_url == '/'
38
+ return routes.unshift([/^\/favicon/i, :file])
39
+ end
40
+
41
+ def call(env)
42
+ path = env["REQUEST_PATH"]
43
+ _, match_method = self.class.routes.detect{ |pattern, _| path =~ pattern }
44
+ return self.send(match_method, env)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,28 @@
1
+
2
+ module Cargobull
3
+ module Service
4
+ @dispatch = []
5
+
6
+ def self.dispatch
7
+ return @dispatch
8
+ end
9
+
10
+ def self.dispatch_to(action)
11
+ return self.dispatch.detect do |klass|
12
+ next klass.name.underscore == action.to_s
13
+ end
14
+ end
15
+
16
+ def self.register(klass)
17
+ @dispatch << klass
18
+ end
19
+
20
+ def self.included(base)
21
+ self.register base
22
+ end
23
+
24
+ def initialize(*args)
25
+ @params = args.shift
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ require 'cargobull'
2
+
3
+ module Cargobull
4
+ module TestHelper
5
+ def response
6
+ return @response || ""
7
+ end
8
+
9
+ [: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
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ include Cargobull::TestHelper
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cargobull
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthias Geier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE.md
20
+ - lib/cargobull.rb
21
+ - lib/cargobull/dispatch.rb
22
+ - lib/cargobull/env.rb
23
+ - lib/cargobull/extensions/string.rb
24
+ - lib/cargobull/initialize.rb
25
+ - lib/cargobull/rackup.rb
26
+ - lib/cargobull/service.rb
27
+ - lib/cargobull/test_helper.rb
28
+ homepage: https://github.com/matthias-geier/cargobull
29
+ licenses:
30
+ - BSD-2
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.1.0
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.2.2
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Multipurpose dispatcher for RESTful services
52
+ test_files: []