ballast 1.0.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.
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"