startback 0.2.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: 0a7f631f93683bc9a9fe0705fc5e3f7df55fa782
4
+ data.tar.gz: 6335d0ff1b733355c96116ce19f9094adea45694
5
+ SHA512:
6
+ metadata.gz: b1bec4146b344fac7d8ef51b130e149fb823e6d10ab5a3050be9165c877585f8dcf38092fa2548c884a8974d97868f0f161d7871908da0117af06fc851e5aaa1
7
+ data.tar.gz: f7482b4b5446cc1557841302cade907c4b597ff704b88ff8017ebf652a92809cf44d5ca24d9c59d0af63dd68b579eed30afd71b5deebc516b0ae94214f6e2cb2
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Startback - Got Your Ruby Back
2
+
3
+ Yet another ruby framework, I'm afraid. Here, we srongly seperate between:
4
+
5
+ 1. the web layer, in charge of a quality HTTP handling
6
+ 2. the operations layer, in charge of the high-level software operations
7
+ 3. the database layer, abstracted using the Relations As First Class Citizen pattern
8
+
9
+ Currently,
10
+
11
+ 1. is handled using extra support on top of Sinatra
12
+ 2. is handled using Startback specific classes
13
+ 3. is handled using Bmg
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ def shell(*cmds)
4
+ cmd = cmds.join("\n")
5
+ puts cmd
6
+ system cmd
7
+ end
8
+
9
+ #
10
+ # Install all tasks found in tasks folder
11
+ #
12
+ # See .rake files there for complete documentation.
13
+ #
14
+ Dir["tasks/*.rake"].each do |taskfile|
15
+ load taskfile
16
+ end
17
+
18
+ task :default => :test
data/lib/startback.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'sinatra'
2
+ require 'rack/robustness'
3
+ require 'finitio'
4
+ require 'logger'
5
+ # Provides a reusable backend framework for backend components written
6
+ # in ruby.
7
+ #
8
+ # The framework installs conventions regarding:
9
+ #
10
+ # - The exposition of web service APIs (Framework::Api, on top of Sinatra)
11
+ # - Operations (Framework::Operation)
12
+ # - Error handling (Framework::Errors) and their handling in web APIs
13
+ # (based on Rack::Robustness)
14
+ # - General code support (Framework::Support modules & classes).
15
+ #
16
+ # Please refer to the documentation of those main abstractions for details.
17
+ #
18
+ module Startback
19
+
20
+ # Simply checks that a path exists of raise an error
21
+ def self._!(path)
22
+ Path(path).tap do |p|
23
+ raise "Missing #{p.basename}." unless p.exists?
24
+ end
25
+ end
26
+
27
+ require_relative 'startback/ext'
28
+ require_relative 'startback/errors'
29
+ require_relative 'startback/support'
30
+ require_relative 'startback/context'
31
+ require_relative 'startback/operation'
32
+ require_relative 'startback/web'
33
+
34
+ # Logger instance to use for the application
35
+ LOGGER = ::Startback::Support::Logger.new
36
+
37
+ end # module Startback
@@ -0,0 +1,16 @@
1
+ module Startback
2
+ #
3
+ # Defines an execution context for Startback applications.
4
+ #
5
+ # This class is aimed at being subclassed for application required
6
+ # extension.
7
+ #
8
+ # In web application, an instance of a context can be set on the Rack
9
+ # environment, using Context::Middleware.
10
+ #
11
+ class Context
12
+ attr_accessor :original_rack_env
13
+
14
+ end # class Context
15
+ end # module Startback
16
+ require_relative 'context/middleware'
@@ -0,0 +1,53 @@
1
+ module Startback
2
+ class Context
3
+ #
4
+ # Rack middleware that installs a particular context instance
5
+ # on the Rack environment.
6
+ #
7
+ # Examples:
8
+ #
9
+ # # Use the default context class
10
+ # Rack::Builder.new do
11
+ # use Startback::Context::Middleware
12
+ #
13
+ # run ->(env){
14
+ # ctx = env[Startback::Context::Middleware::RACK_ENV_KEY]
15
+ # ctx.is_a?(Startback::Context) # => true
16
+ # }
17
+ # end
18
+ #
19
+ # # Use a user defined context class
20
+ # Rack::Builder.new do
21
+ # use Startback::Context::Middleware, context_class: MyContextClass
22
+ #
23
+ # run ->(env){
24
+ # ctx = env[Startback::Context::Middleware::RACK_ENV_KEY]
25
+ # ctx.is_a?(MyContextClass) # => true (your subclass)
26
+ # ctx.is_a?(Startback::Context) # => true (required!)
27
+ # }
28
+ # end
29
+ #
30
+ class Middleware
31
+
32
+ RACK_ENV_KEY = 'SAMBACK_CONTEXT'
33
+
34
+ DEFAULT_OPTIONS = {
35
+ context_class: Context
36
+ }
37
+
38
+ def initialize(app, options = {})
39
+ @app = app
40
+ @options = DEFAULT_OPTIONS.merge(options || {})
41
+ end
42
+ attr_reader :options
43
+
44
+ def call(env)
45
+ env[RACK_ENV_KEY] ||= options[:context_class].new.tap{|c|
46
+ c.original_rack_env = env.dup
47
+ }
48
+ @app.call(env)
49
+ end
50
+
51
+ end # class Middleware
52
+ end # class Context
53
+ end # module Startback
@@ -0,0 +1,91 @@
1
+ module Startback
2
+ module Errors
3
+
4
+ class Error < StandardError
5
+ class << self
6
+
7
+ def status(code = nil)
8
+ @code = code || @code
9
+ end
10
+
11
+ def keep_error(keep = nil)
12
+ @keep_error = keep unless keep.nil?
13
+ @keep_error
14
+ end
15
+ end
16
+
17
+ def message
18
+ msg = super
19
+ return msg unless msg == self.class.name
20
+ parts = self.class.name.split('::').last.gsub(/[A-Z]/){|x|
21
+ " #{x.downcase}"
22
+ }.strip.split(" ")
23
+ parts = parts[0...-1] unless self.class.keep_error
24
+ parts.join(" ").capitalize
25
+ end
26
+ end
27
+
28
+ class BadRequestError < Error
29
+ status 400
30
+ end
31
+
32
+ class UnauthorizedError < BadRequestError
33
+ status 401
34
+ end
35
+
36
+ class ForbiddenError < BadRequestError
37
+ status 403
38
+ end
39
+
40
+ class NotFoundError < BadRequestError
41
+ status 404
42
+ end
43
+
44
+ class MethodNotAllowedError < BadRequestError
45
+ status 405
46
+ end
47
+
48
+ class NotAcceptableError < BadRequestError
49
+ status 406
50
+ end
51
+
52
+ class ConflictError < BadRequestError
53
+ status 409
54
+ end
55
+
56
+ class GoneError < BadRequestError
57
+ status 410
58
+ end
59
+
60
+ class PreconditionFailedError < BadRequestError
61
+ status 412
62
+ end
63
+
64
+ class UnsupportedMediaTypeError < BadRequestError
65
+ status 415
66
+ end
67
+
68
+ class ExpectationFailedError < BadRequestError
69
+ status 417
70
+ end
71
+
72
+ class LockedError < BadRequestError
73
+ status 423
74
+ end
75
+
76
+ class PreconditionRequiredError < BadRequestError
77
+ status 428
78
+ end
79
+
80
+ class InternalServerError < Error
81
+ status 500
82
+ keep_error(true)
83
+ end
84
+
85
+ class NotImplementedError < InternalServerError
86
+ status 501
87
+ end
88
+
89
+ end # module Errors
90
+ include Errors
91
+ end # module Klaro
@@ -0,0 +1,2 @@
1
+ require_relative 'ext/date_time'
2
+ require_relative 'ext/time'
@@ -0,0 +1,9 @@
1
+ class DateTime
2
+
3
+ # Makes sure that DateTime are exported with ISO8601
4
+ # conventions when using to_json and to_csv
5
+ def to_s
6
+ iso8601
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ class Time
2
+
3
+ # Makes sure that Time are exported with ISO8601
4
+ # conventions when using to_json and to_csv
5
+ def to_s
6
+ iso8601
7
+ end
8
+
9
+ end
@@ -0,0 +1,31 @@
1
+ module Startback
2
+ class Operation
3
+ include Errors
4
+
5
+ attr_accessor :world
6
+
7
+ protected :world=
8
+
9
+ def bind(world)
10
+ return self unless world
11
+ dup.tap{|op|
12
+ op.world = world
13
+ }
14
+ end
15
+
16
+ def method_missing(name, *args, &bl)
17
+ return super unless args.empty? and bl.nil?
18
+ return super unless world
19
+ world.fetch(name){ super }
20
+ end
21
+
22
+ protected
23
+
24
+ def run(operation)
25
+ operation.bind(self.world).call
26
+ end
27
+
28
+ end # class Operation
29
+ end # module Startback
30
+ require_relative 'operation/error_operation'
31
+ require_relative 'operation/multi_operation'
@@ -0,0 +1,19 @@
1
+ module Startback
2
+ class Operation
3
+ class ErrorOperation < Operation
4
+
5
+ def initialize(details)
6
+ @details = details
7
+ end
8
+ attr_reader :details
9
+
10
+ def call
11
+ end
12
+
13
+ def bind(world)
14
+ self
15
+ end
16
+
17
+ end # class ErrorOperation
18
+ end # class Operation
19
+ end # module Startback
@@ -0,0 +1,28 @@
1
+ module Startback
2
+ class Operation
3
+ class MultiOperation
4
+
5
+ def initialize(ops = [])
6
+ @ops = ops
7
+ end
8
+ attr_reader :ops
9
+
10
+ def size
11
+ ops.size
12
+ end
13
+
14
+ def +(other)
15
+ MultiOperation.new(@ops + Array(other))
16
+ end
17
+
18
+ def bind(world)
19
+ MultiOperation.new(ops.map{|op| op.bind(world) })
20
+ end
21
+
22
+ def call
23
+ ops.map{|op| op.call }
24
+ end
25
+
26
+ end # class MultiOperation
27
+ end # class Operation
28
+ end # module Startback
@@ -0,0 +1,10 @@
1
+ module Startback
2
+ module Support
3
+
4
+ def logger
5
+ Startback::LOGGER
6
+ end
7
+
8
+ end # module Support
9
+ end # module Startback
10
+ require_relative 'support/logger'
@@ -0,0 +1,34 @@
1
+ module Startback
2
+ module Support
3
+ #
4
+ # A Logger extension that sends info and debug messages to STDOUT
5
+ # and other messages to STDERR. This is not configurable.
6
+ #
7
+ class Logger < ::Logger
8
+
9
+ def initialize
10
+ super(STDOUT)
11
+ @err_logger = ::Logger.new(STDERR)
12
+ end
13
+
14
+ def self.level=(level)
15
+ super.tap{
16
+ @err_logger.level = level
17
+ }
18
+ end
19
+
20
+ def warn(*args, &bl)
21
+ @err_logger.warn(*args, &bl)
22
+ end
23
+
24
+ def error(*args, &bl)
25
+ @err_logger.error(*args, &bl)
26
+ end
27
+
28
+ def fatal(*args, &bl)
29
+ @err_logger.fatal(*args, &bl)
30
+ end
31
+
32
+ end # class Logger
33
+ end # module Support
34
+ end # module Startback
@@ -0,0 +1,8 @@
1
+ module Startback
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 2
5
+ TINY = 0
6
+ end
7
+ VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'web/shield'
2
+ require_relative 'web/catch_all'
3
+ require_relative 'web/health_check'
4
+ require_relative 'web/api'
@@ -0,0 +1,74 @@
1
+ module Startback
2
+ module Web
3
+ class Api < Sinatra::Base
4
+ include Support
5
+ include Errors
6
+
7
+ set :raise_errors, true
8
+ set :show_exceptions, false
9
+
10
+ protected
11
+
12
+ ###
13
+ ### Facade over context
14
+ ###
15
+
16
+ def context
17
+ env[Startback::Context::Middleware::RACK_ENV_KEY]
18
+ end
19
+
20
+ ###
21
+ ### Facade over third party tools
22
+ ###
23
+
24
+ def run(operation)
25
+ operation
26
+ .bind({ context: context })
27
+ .call
28
+ end
29
+
30
+ ###
31
+ ### About the body / input
32
+ ###
33
+
34
+ def loaded_body
35
+ @loaded_body ||= case ctype = request.content_type
36
+ when /json/
37
+ json_body
38
+ when /multipart\/form-data/
39
+ file_body params[:file], Path(file[:filename]).extname
40
+ else
41
+ unsupported_content_type(ctype)
42
+ end
43
+ end
44
+
45
+ def json_body(body = request.body.read)
46
+ JSON.load(body)
47
+ end
48
+
49
+ def file_body(file, ctype)
50
+ raise UnsupportedMediaTypeError, "Unable to use `#{ctype}` as input data"
51
+ end
52
+
53
+ ###
54
+ ### Various reusable responses
55
+ ###
56
+
57
+ def serve_nothing
58
+ [ 204, {}, [] ]
59
+ end
60
+
61
+ def serve(entity_description, entity, ct = :json)
62
+ if entity.nil?
63
+ status 404
64
+ content_type :json
65
+ { description: "#{entity_description} not found" }.to_json
66
+ else
67
+ content_type ct
68
+ entity.to_json
69
+ end
70
+ end
71
+
72
+ end # class Api
73
+ end # module Web
74
+ end # module Startback
@@ -0,0 +1,36 @@
1
+ module Startback
2
+ module Web
3
+ #
4
+ # This Rack middleware catches all exceptions that are raised by sublayers
5
+ # in the Rack chain. It converts them to correct 500 Errors, with a generic
6
+ # exception message encoded in json.
7
+ #
8
+ # This class aims at being used as top level of a Rack chain. It is not
9
+ # aimed at being subclassed.
10
+ #
11
+ # Examples:
12
+ #
13
+ # Rack::Builder.new do
14
+ # use Startback::Web::CatchAll
15
+ # end
16
+ #
17
+ class CatchAll < Rack::Robustness
18
+ include Errors
19
+
20
+ FATAL_ERROR = {
21
+ code: "Gybr::Errors::ServerError",
22
+ description: "An error occured, sorry"
23
+ }.to_json
24
+
25
+ self.catch_all
26
+ self.status 500
27
+ self.content_type 'application/json'
28
+ self.body FATAL_ERROR.to_json
29
+
30
+ self.ensure(true) do |ex|
31
+ Startback::LOGGER.fatal(ex)
32
+ end
33
+
34
+ end # class CatchAll
35
+ end # class Web
36
+ end # module Startback
@@ -0,0 +1,49 @@
1
+ module Startback
2
+ module Web
3
+ #
4
+ # Can be used to easily implement a HealthCheck web service inside a Startback
5
+ # application.
6
+ #
7
+ # Examples:
8
+ #
9
+ # # Returns a 204 with no body
10
+ # run Startback::Web::HealthCheck.new
11
+ #
12
+ # # Returns a 204 with no body
13
+ # run Startback::Web::HealthCheck.new { nil }
14
+ #
15
+ # # Returns a 200 with Ok in plain text
16
+ # run Startback::Web::HealthCheck.new { "Ok" }
17
+ #
18
+ # # Re-raises the exception
19
+ # run Startback::Web::HealthCheck.new { raise "Something bad" }
20
+ #
21
+ # Please note that this rack app is not 100% Rack compliant, since it raises
22
+ # any error that the block itself raises. This class aims at being backed up
23
+ # by a Shield and/or CatchAll middleware.
24
+ #
25
+ # This class is not aimed at being subclassed.
26
+ #
27
+ class HealthCheck
28
+
29
+ def initialize(&bl)
30
+ @checker = bl
31
+ end
32
+
33
+ def call(env)
34
+ if debug_msg = check!(env)
35
+ [ 200, { "Content-Type" => "text/plain" }, debug_msg ]
36
+ else
37
+ [ 204, {}, "" ]
38
+ end
39
+ end
40
+
41
+ protected
42
+
43
+ def check!(env)
44
+ @checker.call if @checker
45
+ end
46
+
47
+ end # class HealthCheck
48
+ end # module Web
49
+ end # module Startback
@@ -0,0 +1,40 @@
1
+ module Startback
2
+ module Web
3
+ #
4
+ # This Rack middleware catches all known exceptions raised by sublayers
5
+ # in the Rack chain. Those exceptions are converted to proper HTTP error
6
+ # codes and friendly error messages encoded in json.
7
+ #
8
+ # Please check the Errors module about status codes used for each Startback
9
+ # error.
10
+ #
11
+ # This class aims at being used as top level of a Rack chain.
12
+ #
13
+ # Examples:
14
+ #
15
+ # Rack::Builder.new do
16
+ # use Startback::Web::Shield
17
+ # end
18
+ #
19
+ class Shield < Rack::Robustness
20
+ include Errors
21
+
22
+ self.no_catch_all
23
+ self.content_type 'application/json'
24
+
25
+ # Decoding errors from json and csv are considered user's fault
26
+ self.on(Finitio::TypeError) { 400 }
27
+
28
+ # Various other codes for the framework specific error classes
29
+ self.on(Startback::Errors::Error) {|ex| ex.class.status }
30
+
31
+ # A bit of logic to choose the best error message for the user
32
+ # according to the error class
33
+ self.body{|ex|
34
+ ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
35
+ { code: ex.class.name, description: ex.message }.to_json
36
+ }
37
+
38
+ end # class Shield
39
+ end # module Web
40
+ end # module Startback
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'startback'
3
+ require 'rack/test'
4
+
5
+ module SpecHelpers
6
+ end
7
+
8
+ RSpec.configure do |c|
9
+ c.include SpecHelpers
10
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ class Context
5
+
6
+ class MyContextSubClass < Context
7
+ end
8
+
9
+ describe Middleware do
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ opts = middleware_options
14
+ Rack::Builder.new do
15
+ use Middleware, opts
16
+ run ->(env){
17
+ ctx = env[Startback::Context::Middleware::RACK_ENV_KEY]
18
+ [200, {}, ctx.class.to_s]
19
+ }
20
+ end
21
+ end
22
+
23
+ context 'when used without option' do
24
+ let(:middleware_options){ nil }
25
+
26
+ it 'sets the default context class' do
27
+ get '/'
28
+ expect(last_response.status).to eql(200)
29
+ expect(last_response.body).to eql("Startback::Context")
30
+ end
31
+ end
32
+
33
+ context 'when specifying the context class' do
34
+ let(:middleware_options){{
35
+ context_class: MyContextSubClass
36
+ }}
37
+
38
+ it 'sets the default context class' do
39
+ get '/'
40
+ expect(last_response.status).to eql(200)
41
+ expect(last_response.body).to eql("Startback::Context::MyContextSubClass")
42
+ end
43
+ end
44
+
45
+ end
46
+ end # module Web
47
+ end # module Startback
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Operation do
5
+
6
+ class FooOp < Operation
7
+
8
+ def initialize(foo = :bar)
9
+ @foo = foo
10
+ end
11
+ attr_accessor :foo
12
+
13
+ def call
14
+ @foo
15
+ end
16
+
17
+ end
18
+
19
+ it 'can be bound, which returns a new operation' do
20
+ foo1 = FooOp.new
21
+ foo1.foo = :bar1
22
+
23
+ foo2 = foo1.bind({ db: :bar })
24
+ expect(foo1 == foo2).to eql(false)
25
+ expect(foo2.foo).to eql(:bar1)
26
+
27
+ expect(->(){ foo1.db }).to raise_error(NoMethodError)
28
+ expect(foo2.db).to eql(:bar)
29
+ end
30
+
31
+ end
32
+
33
+ describe Operation::MultiOperation do
34
+
35
+ it 'lets chain with +' do
36
+ mop = Operation::MultiOperation.new
37
+ mop2 = (mop + FooOp.new)
38
+
39
+ expect(mop == mop2).to eql(false)
40
+ expect(mop.size).to eql(0)
41
+ expect(mop2.size).to eql(1)
42
+ end
43
+
44
+ it 'calls and collects the result on call' do
45
+ mop = Operation::MultiOperation.new + FooOp.new(:hello) + FooOp.new(:world)
46
+ expect(mop.call).to eql([:hello, :world])
47
+ end
48
+
49
+ it 'binds every sub operation recursively' do
50
+ mop = Operation::MultiOperation.new + FooOp.new(:hello) + FooOp.new(:world)
51
+ mop2 = mop.bind({requester: :bar})
52
+
53
+ expect(mop == mop2).to eql(false)
54
+ expect(mop2.ops.all?{|op| op.requester == :bar })
55
+ end
56
+
57
+ end
58
+ end # module Startback
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Support do
5
+ include Support
6
+
7
+ end
8
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ module Web
5
+ describe HealthCheck do
6
+ include Rack::Test::Methods
7
+
8
+ context 'when used without a block and no failure' do
9
+ def app
10
+ HealthCheck.new
11
+ end
12
+
13
+ it 'returns a 204 when ok' do
14
+ get '/'
15
+ expect(last_response.status).to eql(204)
16
+ expect(last_response.body).to be_empty
17
+ end
18
+ end
19
+
20
+ context 'when used without a block a failure' do
21
+ def app
22
+ app = HealthCheck.new
23
+ def app.check!(env)
24
+ raise "Hello error"
25
+ end
26
+ app
27
+ end
28
+
29
+ it 'raises when ko' do
30
+ expect(->(){ get '/' }).to raise_error("Hello error")
31
+ end
32
+ end
33
+
34
+ context 'when used with a block returning a debug message' do
35
+ def app
36
+ HealthCheck.new{ "Hello world" }
37
+ end
38
+
39
+ it 'returns a 200 with plain text message' do
40
+ get '/'
41
+ expect(last_response.status).to eql(200)
42
+ expect(last_response.body).to eql("Hello world")
43
+ end
44
+ end
45
+
46
+ context 'when used with a block raising an exception' do
47
+ def app
48
+ HealthCheck.new{ raise("Hello error") }
49
+ end
50
+
51
+ it 're-raises it' do
52
+ expect(->(){ get '/' }).to raise_error("Hello error")
53
+ end
54
+ end
55
+
56
+ end
57
+ end # module Web
58
+ end # module Startback
data/tasks/gem.rake ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems/package_task'
2
+
3
+ # Dynamically load the gem spec
4
+ gemspec_file = File.expand_path('../../startback.gemspec', __FILE__)
5
+ gemspec = Kernel.eval(File.read(gemspec_file))
6
+
7
+ Gem::PackageTask.new(gemspec) do |t|
8
+
9
+ # Name of the package
10
+ t.name = gemspec.name
11
+
12
+ # Version of the package
13
+ t.version = gemspec.version
14
+
15
+ # Directory used to store the package files
16
+ t.package_dir = "pkg"
17
+
18
+ # True if a gzipped tar file (tgz) should be produced
19
+ t.need_tar = false
20
+
21
+ # True if a gzipped tar file (tar.gz) should be produced
22
+ t.need_tar_gz = false
23
+
24
+ # True if a bzip2'd tar file (tar.bz2) should be produced
25
+ t.need_tar_bz2 = false
26
+
27
+ # True if a zip file should be produced (default is false)
28
+ t.need_zip = false
29
+
30
+ # List of files to be included in the package.
31
+ t.package_files = gemspec.files
32
+
33
+ # Tar command for gzipped or bzip2ed archives.
34
+ t.tar_command = "tar"
35
+
36
+ # Zip command for zipped archives.
37
+ t.zip_command = "zip"
38
+
39
+ end
data/tasks/test.rake ADDED
@@ -0,0 +1,17 @@
1
+ namespace :test do
2
+
3
+ desc "Run RSpec unit tests"
4
+ task :unit do
5
+ system("rspec -Ilib -Ispec --pattern 'spec/unit/**/test_*.rb' --color --backtrace --fail-fast")
6
+ end
7
+
8
+ desc "Run the tests in the examples folder"
9
+ task :example do
10
+ Bundler.with_original_env do
11
+ system("cd example && bundle exec rake")
12
+ end
13
+ end
14
+
15
+ task :all => [:unit, :example]
16
+ end
17
+ task :test => :'test:all'
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: startback
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Bernard Lambeau
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-robustness
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: finitio
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: path
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Yet another ruby backend framework, I'm afraid
112
+ email: blambeau@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - Gemfile
118
+ - README.md
119
+ - Rakefile
120
+ - lib/startback.rb
121
+ - lib/startback/context.rb
122
+ - lib/startback/context/middleware.rb
123
+ - lib/startback/errors.rb
124
+ - lib/startback/ext.rb
125
+ - lib/startback/ext/date_time.rb
126
+ - lib/startback/ext/time.rb
127
+ - lib/startback/operation.rb
128
+ - lib/startback/operation/error_operation.rb
129
+ - lib/startback/operation/multi_operation.rb
130
+ - lib/startback/support.rb
131
+ - lib/startback/support/logger.rb
132
+ - lib/startback/version.rb
133
+ - lib/startback/web.rb
134
+ - lib/startback/web/api.rb
135
+ - lib/startback/web/catch_all.rb
136
+ - lib/startback/web/health_check.rb
137
+ - lib/startback/web/shield.rb
138
+ - spec/spec_helper.rb
139
+ - spec/unit/context/test_middleware.rb
140
+ - spec/unit/test_operation.rb
141
+ - spec/unit/test_support.rb
142
+ - spec/unit/web/test_healthcheck.rb
143
+ - tasks/gem.rake
144
+ - tasks/test.rake
145
+ homepage: http://www.enspirit.be
146
+ licenses:
147
+ - MIT
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 2.6.11
166
+ signing_key:
167
+ specification_version: 4
168
+ summary: Got Your Ruby Back
169
+ test_files: []