ballast 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis-gemfile +15 -0
  4. data/.travis.yml +7 -0
  5. data/.yardopts +1 -0
  6. data/CHANGELOG.md +4 -0
  7. data/Gemfile +21 -0
  8. data/README.md +40 -0
  9. data/Rakefile +28 -0
  10. data/ballast.gemspec +35 -0
  11. data/doc/Ballast/Concerns/Ajax.html +806 -0
  12. data/doc/Ballast/Concerns/Common.html +900 -0
  13. data/doc/Ballast/Concerns/ErrorsHandling.html +283 -0
  14. data/doc/Ballast/Concerns/View.html +664 -0
  15. data/doc/Ballast/Concerns.html +127 -0
  16. data/doc/Ballast/Context.html +417 -0
  17. data/doc/Ballast/Errors/BaseError.html +326 -0
  18. data/doc/Ballast/Errors/InvalidDomain.html +157 -0
  19. data/doc/Ballast/Errors/PerformError.html +157 -0
  20. data/doc/Ballast/Errors/ValidationError.html +157 -0
  21. data/doc/Ballast/Errors.html +125 -0
  22. data/doc/Ballast/Operation.html +1304 -0
  23. data/doc/Ballast/OperationsChain.html +585 -0
  24. data/doc/Ballast/Version.html +189 -0
  25. data/doc/Ballast.html +130 -0
  26. data/doc/_index.html +267 -0
  27. data/doc/class_list.html +54 -0
  28. data/doc/css/common.css +1 -0
  29. data/doc/css/full_list.css +57 -0
  30. data/doc/css/style.css +338 -0
  31. data/doc/file.README.html +115 -0
  32. data/doc/file_list.html +56 -0
  33. data/doc/frames.html +26 -0
  34. data/doc/index.html +115 -0
  35. data/doc/js/app.js +219 -0
  36. data/doc/js/full_list.js +178 -0
  37. data/doc/js/jquery.js +4 -0
  38. data/doc/method_list.html +269 -0
  39. data/doc/top-level-namespace.html +112 -0
  40. data/lib/ballast/concerns/ajax.rb +116 -0
  41. data/lib/ballast/concerns/common.rb +97 -0
  42. data/lib/ballast/concerns/errors_handling.rb +49 -0
  43. data/lib/ballast/concerns/view.rb +63 -0
  44. data/lib/ballast/context.rb +38 -0
  45. data/lib/ballast/errors.rb +34 -0
  46. data/lib/ballast/operation.rb +136 -0
  47. data/lib/ballast/operations_chain.rb +38 -0
  48. data/lib/ballast/version.rb +24 -0
  49. data/lib/ballast.rb +24 -0
  50. data/spec/ballast/concerns/ajax_spec.rb +124 -0
  51. data/spec/ballast/concerns/common_spec.rb +100 -0
  52. data/spec/ballast/concerns/errors_handling_spec.rb +63 -0
  53. data/spec/ballast/concerns/view_spec.rb +107 -0
  54. data/spec/ballast/context_spec.rb +23 -0
  55. data/spec/ballast/errors_spec.rb +16 -0
  56. data/spec/ballast/operation_spec.rb +175 -0
  57. data/spec/ballast/operations_chain_spec.rb +33 -0
  58. data/spec/coverage_helper.rb +19 -0
  59. data/spec/spec_helper.rb +19 -0
  60. metadata +225 -0
@@ -0,0 +1,116 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ # A set of concerns to address common issues.
8
+ module Concerns
9
+ # A concern to handle AJAX and HTTP requests.
10
+ module Ajax
11
+ extend ActiveSupport::Concern
12
+
13
+ # Checks if the current request is AJAX.
14
+ #
15
+ # @return [Boolean] `true` if the request is AJAX, `false` otherwise.
16
+ def is_ajax?
17
+ (request.respond_to?(:xhr?) && request.xhr?) || params[:xhr].to_boolean
18
+ end
19
+
20
+ # Prepares an AJAX response.
21
+ #
22
+ # @param status [Symbol|Fixnum] The HTTP status of the response.
23
+ # @param data [Object] Additional data to append to the response.
24
+ # @param error [Object] A error to append to the response.
25
+ def prepare_ajax(status = :ok, data = nil, error = nil)
26
+ rv = {status: status}.ensure_access(:indifferent)
27
+ rv[:error] = error if error.present?
28
+ rv[:data] = data if data.present?
29
+ rv
30
+ end
31
+
32
+ # Sends an AJAX response to the client.
33
+ #
34
+ # @param data [Hash] The response to send.
35
+ # @param status [Symbol|Fixnum] The HTTP status of the response, *ignored if already set in data*.
36
+ # @param format [Symbol] The content type of the response.
37
+ def send_ajax(data, status: :ok, format: :json)
38
+ if !performed? then
39
+ # Prepare data
40
+ data = prepare_ajax_send(data, status)
41
+
42
+ # Setup callback and format
43
+ format, callback, content_type = format_ajax_send(format)
44
+ status = data[:status]
45
+
46
+ # Prepare data for formatting
47
+ data = ActiveSupport::JSON.encode(data) if [:json, :jsonp, :pretty_json, :pretty_jsonp, :text].include?(format)
48
+
49
+ # Render
50
+ render(format => data, status: status, callback: callback, content_type: content_type)
51
+ end
52
+ end
53
+
54
+ # Updates an AJAX response from a operation, taking either the response data or the first error.
55
+ #
56
+ # @param data [Hash] The current data.
57
+ # @param operation [Operation] The operation to gather data from.
58
+ # @return [Hash] The updated data.
59
+ def update_ajax(data, operation = nil)
60
+ operation ||= @operation
61
+ data.merge!(operation.success? ? {data: operation.response[:data]} : {error: operation.errors.first})
62
+ data
63
+ end
64
+
65
+ # Prevents HTTP caching.
66
+ def prevent_caching
67
+ response.headers.merge!({
68
+ "Cache-Control" => "no-cache, no-store, max-age=0, must-revalidate",
69
+ "Pragma" => "no-cache",
70
+ "Expires" => "Fri, 01 Jan 1990 00:00:00 GMT"
71
+ })
72
+ end
73
+
74
+ # Allows HTTP Cross-Origin Resource Sharing.
75
+ def allow_cors
76
+ headers.merge!({
77
+ "Access-Control-Allow-Origin" => "*",
78
+ "Access-Control-Allow-Methods" => "POST, GET, OPTIONS",
79
+ "Access-Control-Allow-Headers" => "*",
80
+ "Access-Control-Max-Age" => 1.year.to_i.to_s
81
+ })
82
+ end
83
+
84
+ # Disallows web robots.
85
+ def disallow_robots
86
+ render(text: "User-agent: *\nDisallow: /", content_type: "text/plain")
87
+ end
88
+
89
+ private
90
+ # Prepares data for sending back to the client.
91
+ #
92
+ # @param data [Object] The data to send back. Can be a full response or partial data.
93
+ # @param status [Symbol|Fixnum] The HTTP status to set if a new response must be created.
94
+ # @return [Hash] An HTTP response.
95
+ def prepare_ajax_send(data, status)
96
+ data = prepare_ajax(status, data) if !data.is_a?(Hash)
97
+ data[:status] ||= status
98
+ data[:status] = Rack::Utils.status_code(data[:status].to_s.to_sym) if !data[:status].is_a?(Fixnum)
99
+ data
100
+ end
101
+
102
+ # Sets up parameters to send a response.
103
+ #
104
+ # @param format [Symbol] The format of the data.
105
+ # @return [Array] An array of format, callback and content_type.
106
+ def format_ajax_send(format)
107
+ format ||= params[:format] || request.format || "json"
108
+ format = format.to_sym
109
+ callback = format == :jsonp ? (params[:callback] || "jsonp#{Time.now.to_i}") : nil
110
+ content_type = (format == :text) ? "text/plain" : nil
111
+
112
+ [format, callback, content_type]
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,97 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ module Concerns
8
+ # A concern to handle common tasks in an application.
9
+ module Common
10
+ # Checks if the user is sending any data.
11
+ #
12
+ # @return [Boolean] `true` if the user is sending data, `false` otherwise.
13
+ def sending_data?
14
+ request.post? || request.put?
15
+ end
16
+
17
+ # Performs an operation, using itself as owner by default.
18
+ #
19
+ # @param klass [Class] The operation to perform.
20
+ # @param owner [Object] The owner to use. By default it uses itself.
21
+ # @param kwargs [Hash] The arguments for performing.
22
+ # @return [Operation] The performed operation
23
+ def perform_operation(klass, owner = nil, **kwargs)
24
+ @operation = klass.perform(owner || self, **kwargs)
25
+ end
26
+
27
+ # Formats a relative date using abbreviation or short formats.
28
+ #
29
+ # @param date [DateTime] The date to format.
30
+ # @param reference [DateTime] The reference date.
31
+ # @param suffix [String] The suffix to add to the formatted date.
32
+ # @return [String] The formatted date.
33
+ def format_short_duration(date, reference = nil, suffix = "")
34
+ reference ||= Time.now
35
+ amount = (reference.to_i - date.to_i).to_i
36
+
37
+ if amount <= 0 then
38
+ "now"
39
+ elsif amount < 1.day then
40
+ format_short_amount(amount, suffix)
41
+ elsif amount < 1.year then
42
+ date.strftime("%b %d")
43
+ else
44
+ date.strftime("%b %d %Y")
45
+ end
46
+ end
47
+
48
+ # Formats a short amount of time (less than one hour).
49
+ #
50
+ # @param amount [Fixnum] The amount to format.
51
+ # @param suffix [String] The suffix to add to the formatted amount.
52
+ # @return [String] The formatted amount.
53
+ def format_short_amount(amount, suffix)
54
+ if amount < 1.minute then
55
+ "#{amount.floor}s#{suffix}"
56
+ elsif amount < 1.hour then
57
+ "#{(amount / 60).floor}m#{suffix}"
58
+ else
59
+ "#{(amount / 3600).floor}h#{suffix}"
60
+ end
61
+ end
62
+
63
+ # Formats a long date.
64
+ #
65
+ # @param date [DateTime] The date to format.
66
+ # @param separator [String] The separator between date and time.
67
+ # @param format [String] The format of the date, like in strftime. Use `%-` for the separator, `%o` for the ordinalized version of the day of the month
68
+ # and `%:Z` for the zone name considering also DST.
69
+ def format_long_date(date, separator = "•", format = "%I:%M%p %- %b %o, %Y (%:Z)")
70
+ tz = Time.zone
71
+ replacements = {"%-" => separator, "%o" => date.day.ordinalize, "%:Z" => tz.send(tz.uses_dst? && date.dst? ? :dst_name : :name)}
72
+ date.strftime(format).gsub(/%(-|o|(:Z))/) {|r| replacements.fetch(r, r) }
73
+ end
74
+
75
+ # Authenticates a user via HTTP, handling the error if the authentication failed.
76
+ #
77
+ # @param area [String] The name of the area.
78
+ # @param title [String] A title for authentication errors.
79
+ # @param message [String] A message for authentication errors.
80
+ # @param authenticator [Proc] A block to verify if authentication is valid.
81
+ def authenticate_user(area = nil, title = nil, message = nil, &authenticator)
82
+ area ||= "Private Area"
83
+ title ||= "Authentication required."
84
+ message ||= "To view this resource you have to authenticate."
85
+ authenticated = authenticate_with_http_basic { |username, password| authenticator.call(username, password) }
86
+
87
+ if !authenticated then
88
+ headers["WWW-Authenticate"] = "Basic realm=\"#{area}\""
89
+ @error_title = title
90
+ @error_code = 401
91
+ @error_message = message
92
+ handle_error
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ module Concerns
8
+ # A concern to handle errors.
9
+ module ErrorsHandling
10
+ extend ActiveSupport::Concern
11
+
12
+ # Handles an error in the application.
13
+ #
14
+ # @param exception [Hash|Exception] The exception to handle.
15
+ # @param layout [String] The layout to use to render the error.
16
+ # @param title [String] The title to set in case of custom errors.
17
+ def handle_error(exception = nil, layout = "error", title = "Error - Application")
18
+ @error ||= exception
19
+
20
+ if @error.is_a?(Lazier::Exceptions::Debug) then
21
+ @error_title = "Debug"
22
+ @error_code = 503
23
+ elsif @error.is_a?(Hash) then
24
+ @error_title = title
25
+ @error_code = @error[:status]
26
+ @error_message = @error[:error]
27
+ else
28
+ @error_title = "Error - #{@error.class.to_s}"
29
+ @error_code = 500
30
+ end
31
+
32
+ send_or_render_error(layout)
33
+ end
34
+
35
+ private
36
+ # Send an AJAX error o renders it.
37
+ #
38
+ # @param layout [String] The layout to use to render the error.
39
+ def send_or_render_error(layout)
40
+ if is_ajax? then
41
+ data = prepare_ajax(@error_code, {type: @error_title, backtrace: @error.backtrace.join("\n")}, @error_message || @error.message)
42
+ send_ajax(data)
43
+ else
44
+ render(nothing: true, status: @error_code, layout: layout, formats: [:html])
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,63 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ module Concerns
8
+ # A concern to help view handling.
9
+ module View
10
+ # Scopes the CSS of the current page using the controller and action name.
11
+ #
12
+ # @return [String] The scoped string.
13
+ def scope_css
14
+ "%s %s" % [controller_path.gsub("/", "-"), action_name]
15
+ end
16
+
17
+ # Returns an instance of the browser.
18
+ #
19
+ # @return [Browser] A browser object.
20
+ def browser
21
+ @browser ||= Brauser::Browser.new(request.user_agent)
22
+ end
23
+
24
+ # Checks if the current browser is supported according to a definition YAML file.
25
+ #
26
+ # @param conf_file [String] The configuration file which holds the definitions.
27
+ # @return [Boolean] `true` if the browser is supported, `false` otherwise.
28
+ def browser_supported?(conf_file = nil)
29
+ conf_file ||= (Rails.root + "config/supported-browsers.yml").to_s if defined?(Rails)
30
+ browser.supported?(conf_file)
31
+ end
32
+
33
+ # Outputs the Javascript parameters.
34
+ #
35
+ # @param as_html [Boolean] Whether to return the parameters as HTML rather than hash.
36
+ # @param tag [Symbol] The tag to use for HTML.
37
+ # @param id [String] The id for the tag.
38
+ # @return [String|Hash] Javascript parameters as HTML or the hash.
39
+ def javascript_params(as_html = true, tag = :details, id = nil)
40
+ as_html ? content_tag(tag, @javascript_params.to_json.html_safe, "data-jid" => id): @javascript_params
41
+ end
42
+
43
+ # Appends new Javascript parameters.
44
+ #
45
+ # @param key [String|Symbol] The key of the new parameters. If `nil`, the root will be merged/replaced.
46
+ # @param data [Hash] The data to add.
47
+ # @param replace [Boolean] Whether to replace existing data rather than merge.
48
+ def add_javascript_params(key, data, replace = false)
49
+ @javascript_params ||= HashWithIndifferentAccess.new
50
+
51
+ if key
52
+ @javascript_params[key] = nil if replace
53
+ @javascript_params[key] ||= {}
54
+ @javascript_params[key].merge!(data)
55
+ elsif replace
56
+ @javascript_params = data.with_indifferent_access
57
+ else
58
+ @javascript_params.merge!(data)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,38 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ # A context for an operation. It is basically a Hash with few enhancements, like owner, errors and output support.
8
+ class Context < Interactor::Context
9
+ # Builds a new context.
10
+ #
11
+ # @param owner [Object] The owner of this context.
12
+ # @param additional [Hash] Additional parameters to include into the context.
13
+ def self.build(owner, additional = {})
14
+ super({
15
+ owner: owner,
16
+ errors: [],
17
+ output: nil,
18
+ response: HashWithIndifferentAccess.new
19
+ }.merge(additional).ensure_access(:indifferent))
20
+ end
21
+
22
+ # Lookups missing methods in the delegatee hash.
23
+ #
24
+ # @param method [Symbol] The method to lookup.
25
+ # @param args [Array] The arguments passed to the method. *This is ignored.*
26
+ # @param block [Proc] The block passed to the method. *This is ignored.*
27
+ # @return [Object] The value for the method, if present.
28
+ def method_missing(method, *args, &block)
29
+ object = __getobj__
30
+
31
+ if object[method] then
32
+ object[method]
33
+ else
34
+ super(method, *args, &block)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ # Common errors raised by a Rails application.
8
+ module Errors
9
+ # The base error raised from an application.
10
+ #
11
+ # @attribute [r] response
12
+ # @return [String|Hash] The response which contains either a message or an hash with status code and a error message.
13
+ class BaseError < RuntimeError
14
+ attr_reader :response
15
+
16
+ def initialize(msg = nil)
17
+ super(msg)
18
+ @response = msg
19
+ end
20
+ end
21
+
22
+ # This is raised when an invalid domain is requested.
23
+ class InvalidDomain < BaseError
24
+ end
25
+
26
+ # This is raised when something went wrong during the processing of a operation.
27
+ class PerformError < BaseError
28
+ end
29
+
30
+ # This is raised when some invalid parameters are passed to a operation.
31
+ class ValidationError < BaseError
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,136 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ # A operation represents a single responsibility class. Subclasses should only expose and override the #perform method.
8
+ class Operation
9
+ extend ::Forwardable
10
+ include Interactor
11
+ def_delegators :context, :owner, :errors, :response, :output
12
+
13
+ # Performs the operation.
14
+ #
15
+ # @param owner_or_context [Object|Context] If is a context, then it will be the context of the operation, otherwise a blank a context with the object
16
+ # as owner will be created.
17
+ # @param context [NilClass] The context for the operation. *Ignored if `owner_or_context` is a context.*
18
+ # @param params [Hash] The additional parameters for the new context. *Ignored if `owner_or_context` is a context.*
19
+ # @return [Operation] The performed operation.
20
+ def self.perform(owner_or_context, context: nil, params: {})
21
+ arg = owner_or_context
22
+ arg = (context || ::Ballast::Context.build(owner_or_context, params)) if !arg.is_a?(::Ballast::Context)
23
+ super(arg)
24
+ end
25
+
26
+ # Creates a new operation.
27
+ #
28
+ # @param context [Context] The context for the operation.
29
+ def initialize(context)
30
+ @context = context
31
+ setup
32
+ end
33
+
34
+ # Sets up the response hash from instance variables.
35
+ #
36
+ # @param force [Boolean] Whether to setup the response even if the operation failed.
37
+ # @return [Hash] The response hash.
38
+ def setup_response(force = false)
39
+ if success? || force then
40
+ vars = instance_variables
41
+ vars.delete(:@context)
42
+
43
+ context.response.merge!(vars.reduce({}){ |rv, var|
44
+ rv[var.to_s.gsub(/[:@]/, "")] = instance_variable_get(var)
45
+ rv
46
+ })
47
+ end
48
+
49
+ context.response
50
+ end
51
+
52
+ # Imports the response hash into the target instance variables.
53
+ #
54
+ # @param target [Object] The target of the import.
55
+ # @param fields [Array] The keys to import.
56
+ # @param overwrite [Boolean] Whether to overwrite existing variables into the target. If set to `false`, any overwrite will raise an `ArgumentError`.
57
+ def import_response(target, *fields, overwrite: true)
58
+ fields.each do |field|
59
+ raise ArgumentError.new(field) if target.instance_variable_get("@#{field}") && !overwrite
60
+ target.instance_variable_set("@#{field}", response[field])
61
+ end
62
+ end
63
+
64
+ # Performs the operation handling base errors.
65
+ #
66
+ # @param setup_response_after [Boolean] Whether to setup the response after processing.
67
+ def perform_with_handling(setup_response_after = true)
68
+ begin
69
+ yield
70
+ rescue Lazier::Exceptions::Debug => de
71
+ raise de
72
+ rescue => e
73
+ e.is_a?(::Ballast::Errors::BaseError) ? fail!(e.response) : raise(e)
74
+ end
75
+
76
+ setup_response if setup_response_after
77
+ end
78
+
79
+ # Marks failure of the operation appending the error to the context.
80
+ #
81
+ # @param error [Object|NilClass] The error to store.
82
+ def fail!(error = nil)
83
+ errors << error if error
84
+ super()
85
+ end
86
+
87
+ # Imports the current operation errors into the target's `@error` instance variable or in the flash hash.
88
+ #
89
+ # @param target [Object] The target of the import.
90
+ # @param to_flash [Boolean] If to import the error in the target's flash object rather than the instance variable.
91
+ # @param first_only [Boolean] If to only import the first error.
92
+ def import_error(target, to_flash = true, first_only = true)
93
+ values = errors
94
+ values = values.map {|v| v[:error] } if to_flash
95
+ values = values.first if first_only
96
+
97
+ if to_flash then
98
+ target.flash[:error] = values
99
+ else
100
+ target.instance_variable_set(:@error, values)
101
+ end
102
+ end
103
+
104
+ # Resolves a numeric error to a human readable message.
105
+ #
106
+ # @param error [BaseError|Fixnum] The error to resolve.
107
+ # @param supported_messages [Hash] The list of supported error codes.
108
+ # @param only_message [Boolean] If to only return the message string rather than a full error hash.
109
+ # @return [String|Hash] The error with a human readable message or the message alone.
110
+ def resolve_error(error, supported_messages = {}, only_message = false)
111
+ code = (error.respond_to?(:response) ? error.response : 500).to_integer(500)
112
+ rv = {status: code, error: supported_messages.fetch(code, "Oops! We're having some issue. Please try again later.")}
113
+ only_message ? rv[:error] : rv
114
+ end
115
+
116
+ # If running under eventmachine, run the block in a thread of its threadpool using EM::Synchrony, otherwise run the block normally.
117
+ #
118
+ # @param block [Proc] The block to run.
119
+ def in_em_thread(&block)
120
+ EM.reactor_running? ? EM::Synchrony.defer(&block) : block.call
121
+ end
122
+
123
+ # Forwards any missing method to the owner.
124
+ #
125
+ # @param method [Symbol] The method to forward.
126
+ # @param args [Array] The arguments to pass to the method.
127
+ # @param block [Proc] The block to pass to the method.
128
+ def method_missing(method, *args, &block)
129
+ if owner.respond_to?(method)
130
+ owner.send(method, *args, &block)
131
+ else
132
+ super(method, *args, &block)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,38 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Ballast
7
+ # A operation made of several operation run sequentially passing the common context. The chain will stop on the first failure.
8
+ #
9
+ # @attribute [r] operations
10
+ # @return [Array] The list of operations performed.
11
+ class OperationsChain < Operation
12
+ include ::Interactor::Organizer
13
+ attr_reader :operations
14
+
15
+ # Performs the chain.
16
+ #
17
+ # @param argument [Object|Context] If is a context, then it will be the context of the operation, unless a blank a context with the object
18
+ # as owner will be created.
19
+ # @param operations [Array] The list of operations to perform.
20
+ # @param context [NilClass] The context for the operation. *Ignored if `owner_or_context` is a context.*
21
+ # @param params [Hash] The additional parameters for the new context. *Ignored if `owner_or_context` is a context.*
22
+ # @return [Operation] The performed chain.
23
+ def self.perform(argument, operations, context: nil, params: {})
24
+ argument = (context || ::Ballast::Context.build(argument, params)) if !argument.is_a?(::Ballast::Context)
25
+ new(operations, argument).tap(&:perform)
26
+ end
27
+
28
+ # Creates a new chain.
29
+ #
30
+ # @param operations [Array] The list of operations to perform.
31
+ # @param context [Context] The context for the chain.
32
+ def initialize(operations, context)
33
+ @context = context
34
+ @operations = operations.ensure_array
35
+ setup
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ # A collection of base utilities for Ruby on Rails.
7
+ module Ballast
8
+ # The current version of ballast, according to semantic versioning.
9
+ #
10
+ # @see http://semver.org
11
+ module Version
12
+ # The major version.
13
+ MAJOR = 1
14
+
15
+ # The minor version.
16
+ MINOR = 0
17
+
18
+ # The patch version.
19
+ PATCH = 0
20
+
21
+ # The current version of ballast.
22
+ STRING = [MAJOR, MINOR, PATCH].compact.join(".")
23
+ end
24
+ end
data/lib/ballast.rb ADDED
@@ -0,0 +1,24 @@
1
+ #
2
+ # This file is part of the ballast gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "lazier"
7
+ require "brauser"
8
+ require "interactor"
9
+ require "addressable/uri"
10
+ require "rack/utils"
11
+ require "rack/fiber_pool"
12
+ require "em-synchrony"
13
+
14
+ Lazier.load!
15
+
16
+ require "ballast/version" if !defined?(Ballast::Version)
17
+ require "ballast/errors"
18
+ require "ballast/context"
19
+ require "ballast/operation"
20
+ require "ballast/operations_chain"
21
+ require "ballast/concerns/ajax"
22
+ require "ballast/concerns/common"
23
+ require "ballast/concerns/view"
24
+ require "ballast/concerns/errors_handling"