ballast 1.9.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +35 -0
  3. data/.travis-gemfile +4 -5
  4. data/.travis.yml +3 -2
  5. data/CHANGELOG.md +62 -6
  6. data/Gemfile +7 -8
  7. data/README.md +2 -2
  8. data/ballast.gemspec +9 -12
  9. data/doc/Ballast/AjaxResponse.html +1380 -0
  10. data/doc/Ballast/Concerns/AjaxHandling.html +662 -0
  11. data/doc/Ballast/Concerns/Common.html +81 -361
  12. data/doc/Ballast/Concerns/ErrorsHandling.html +18 -36
  13. data/doc/Ballast/Concerns/View.html +181 -157
  14. data/doc/Ballast/Concerns.html +6 -6
  15. data/doc/Ballast/Configuration.html +204 -31
  16. data/doc/Ballast/Emoji/Character.html +411 -0
  17. data/doc/Ballast/Emoji/Utils.html +794 -0
  18. data/doc/Ballast/Emoji.html +125 -0
  19. data/doc/Ballast/Errors/{BaseError.html → Base.html} +61 -34
  20. data/doc/Ballast/Errors/{PerformError.html → Failure.html} +21 -17
  21. data/doc/Ballast/Errors/InvalidDomain.html +11 -11
  22. data/doc/Ballast/Errors/{ValidationError.html → ValidationFailure.html} +24 -16
  23. data/doc/Ballast/Errors.html +5 -5
  24. data/doc/Ballast/Middlewares/DefaultHost.html +6 -6
  25. data/doc/Ballast/Middlewares.html +4 -4
  26. data/doc/Ballast/RequestDomainMatcher.html +28 -28
  27. data/doc/Ballast/Service/Response.html +1243 -0
  28. data/doc/Ballast/Service.html +1314 -0
  29. data/doc/Ballast/Version.html +7 -7
  30. data/doc/Ballast.html +15 -15
  31. data/doc/_index.html +59 -30
  32. data/doc/class_list.html +6 -2
  33. data/doc/css/style.css +1 -0
  34. data/doc/file.README.html +6 -6
  35. data/doc/file_list.html +5 -1
  36. data/doc/frames.html +1 -1
  37. data/doc/index.html +6 -6
  38. data/doc/js/full_list.js +4 -1
  39. data/doc/method_list.html +167 -79
  40. data/doc/top-level-namespace.html +41 -4
  41. data/lib/ballast/ajax_response.rb +76 -0
  42. data/lib/ballast/concerns/ajax_handling.rb +73 -0
  43. data/lib/ballast/concerns/common.rb +25 -47
  44. data/lib/ballast/concerns/errors_handling.rb +21 -30
  45. data/lib/ballast/concerns/view.rb +24 -22
  46. data/lib/ballast/configuration.rb +30 -10
  47. data/lib/ballast/emoji.rb +114 -0
  48. data/lib/ballast/errors.rb +16 -13
  49. data/lib/ballast/middlewares/default_host.rb +3 -3
  50. data/lib/ballast/request_domain_matcher.rb +7 -7
  51. data/lib/ballast/service.rb +147 -0
  52. data/lib/ballast/version.rb +3 -3
  53. data/lib/ballast.rb +22 -22
  54. data/spec/ballast/ajax_response_spec.rb +61 -0
  55. data/spec/ballast/concerns/ajax_handling_spec.rb +86 -0
  56. data/spec/ballast/concerns/common_spec.rb +17 -52
  57. data/spec/ballast/concerns/errors_handling_spec.rb +35 -29
  58. data/spec/ballast/concerns/view_spec.rb +21 -32
  59. data/spec/ballast/configuration_spec.rb +66 -16
  60. data/spec/ballast/emoji_spec.rb +103 -0
  61. data/spec/ballast/errors_spec.rb +5 -5
  62. data/spec/ballast/middlewares/default_host_spec.rb +3 -5
  63. data/spec/ballast/request_domain_matcher_spec.rb +4 -4
  64. data/spec/ballast/service_spec.rb +137 -0
  65. data/spec/spec_helper.rb +1 -13
  66. metadata +42 -80
  67. data/doc/Ballast/Concerns/Ajax.html +0 -945
  68. data/doc/Ballast/Context.html +0 -417
  69. data/doc/Ballast/Operation.html +0 -1304
  70. data/doc/Ballast/OperationsChain.html +0 -597
  71. data/lib/ballast/concerns/ajax.rb +0 -134
  72. data/lib/ballast/context.rb +0 -38
  73. data/lib/ballast/operation.rb +0 -136
  74. data/lib/ballast/operations_chain.rb +0 -45
  75. data/spec/ballast/concerns/ajax_spec.rb +0 -141
  76. data/spec/ballast/context_spec.rb +0 -23
  77. data/spec/ballast/operation_spec.rb +0 -177
  78. data/spec/ballast/operations_chain_spec.rb +0 -61
@@ -0,0 +1,147 @@
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 class which implements a common abstraction for services.
8
+ #
9
+ # @attribute [r] owner
10
+ # @return [Object|NilClass] The owner of this service.
11
+ class Service
12
+ # A response to a service invocation.
13
+ #
14
+ # @attribute [r] success
15
+ # @return [Boolean] Whether the invocation was successful or not.
16
+ # @attribute [r] data
17
+ # @return [Object] The data returned by the operation.
18
+ # @attribute [r] errors
19
+ # @return [Array] The errors returned by the operation.
20
+ class Response
21
+ attr_reader :success, :data, :errors
22
+
23
+ # Creates a new service response.
24
+ #
25
+ # @param success [Boolean] Whether the invocation was successful or not.
26
+ # @param data [Object|NilClass] The data returned by the operation.
27
+ # @param errors [Array|NilClass] The errors returned by the operation.
28
+ # @param error [Object|NilClass] Alias for errors. *Ignored if `errors` is present.*
29
+ def initialize(success = true, data: nil, errors: nil, error: nil)
30
+ errors ||= error.ensure_array
31
+
32
+ @success = success.to_boolean
33
+ @data = data
34
+ @errors = errors.ensure_array(no_duplicates: true, compact: true)
35
+ end
36
+
37
+ # Returns whether the invocation was successful or not.
38
+ #
39
+ # @return [Boolean] `true` if the service invocation was successful, `false` otherwise.
40
+ def success?
41
+ # TODO@PI: Ignore rubocop on this
42
+ @success
43
+ end
44
+ alias_method :successful?, :success?
45
+ alias_method :succeeded?, :success?
46
+
47
+ # Returns whether the invocation failed or not.
48
+ #
49
+ # @return [Boolean] `true` if the service invocation failed, `false` otherwise.
50
+ def fail?
51
+ !@success
52
+ end
53
+ alias_method :failed?, :fail?
54
+
55
+ # Returns the first error returned by the operation.
56
+ #
57
+ # @return [Object] The first error returned by the service.
58
+ def error
59
+ @errors.first
60
+ end
61
+
62
+ # Converts this response to a AJAX response.
63
+ #
64
+ # @return [AjaxResponse] The AJAX response, which will include only the first error.
65
+ def as_ajax_response
66
+ status, error_message =
67
+ if successful?
68
+ [:ok, nil]
69
+ elsif error.is_a?(Hash)
70
+ [error[:status], error[:error]]
71
+ else
72
+ [:unknown, error]
73
+ end
74
+
75
+ AjaxResponse.new(status: status, data: data, error: error_message)
76
+ end
77
+ end
78
+
79
+ attr_reader :owner
80
+
81
+ # Invokes one of the operations exposed by the service.
82
+ #
83
+ # @param operation [String] The operation to invoke.
84
+ # @param owner [Object|NilClass] The owner of the service.
85
+ # @param raise_errors [Boolean] Whether to raise errors instead of returning a failure.
86
+ # @param params [Hash] The parameters to pass to the service.
87
+ # @param kwargs [Hash] Other modifiers to pass to the service.
88
+ # @param block [Proc] A lambda to pass to the service.
89
+ # @return [Response] The response of the service.
90
+ def self.call(operation = :perform, owner: nil, raise_errors: false, params: {}, **kwargs, &block)
91
+ fail!(status: 501, error: "Unsupported operation #{self}.#{operation}.") unless respond_to?(operation)
92
+ Response.new(true, data: send(operation, owner: owner, params: params, **kwargs, &block))
93
+ rescue Errors::Failure => failure
94
+ handle_failure(failure, raise_errors)
95
+ end
96
+
97
+ # Marks the failure of the operation.
98
+ #
99
+ # @param details [Object] The error(s) occurred.
100
+ # @param on_validation [Boolean] Whether the error(s) was/were validation error(s).
101
+ def self.fail!(details, on_validation: false)
102
+ raise(on_validation ? Errors::ValidationFailure : Errors::Failure, details)
103
+ end
104
+
105
+ # Creates a service object.
106
+ #
107
+ # @param owner [Object|NilClass] The owner of the service.
108
+ def initialize(owner = nil)
109
+ @owner = owner
110
+ end
111
+
112
+ # Invokes one of the operations exposed by the service.
113
+ #
114
+ # @param operation [String] The operation to invoke.
115
+ # @param owner [Object|NilClass] The owner of the service.
116
+ # @param raise_errors [Boolean] Whether to raise errors instead of returning a failure.
117
+ # @param params [Hash] The parameters to pass to the service.
118
+ # @param kwargs [Hash] Other modifiers to pass to the service.
119
+ # @param block [Proc] A lambda to pass to the service.
120
+ # @return [Response] The response of the service.
121
+ def call(operation = :perform, owner: nil, raise_errors: false, params: {}, **kwargs, &block)
122
+ # PI: Ignore Roodi on this method
123
+ @owner = owner if owner
124
+ fail!(status: 501, error: "Unsupported operation #{self.class}##{operation}.") unless respond_to?(operation)
125
+ Response.new(true, data: send(operation, params: params, **kwargs, &block))
126
+ rescue Errors::Failure => failure
127
+ self.class.send(:handle_failure, failure, raise_errors)
128
+ end
129
+
130
+ # Marks the failure of the operation.
131
+ #
132
+ # @param details [Object] The error(s) occurred.
133
+ # @param on_validation [Boolean] Whether the error(s) was/were validation error(s).
134
+ def fail!(details, on_validation: false)
135
+ self.class.fail!(details, on_validation: on_validation)
136
+ end
137
+
138
+ # Handles a failure.
139
+ #
140
+ # @param failure [Failure] The failure to handle.
141
+ # @param raise_errors [Boolean] If `true` it will simply raise the error, otherwise it will return a failure as as Service::Response.
142
+ # @return [Response] A failure response.
143
+ def self.handle_failure(failure, raise_errors)
144
+ raise_errors ? raise(failure) : Response.new(false, error: failure.details)
145
+ end
146
+ end
147
+ end
@@ -10,13 +10,13 @@ module Ballast
10
10
  # @see http://semver.org
11
11
  module Version
12
12
  # The major version.
13
- MAJOR = 1
13
+ MAJOR = 2
14
14
 
15
15
  # The minor version.
16
- MINOR = 9
16
+ MINOR = 0
17
17
 
18
18
  # The patch version.
19
- PATCH = 3
19
+ PATCH = 0
20
20
 
21
21
  # The current version of ballast.
22
22
  STRING = [MAJOR, MINOR, PATCH].compact.join(".")
data/lib/ballast.rb CHANGED
@@ -3,40 +3,41 @@
3
3
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
4
  #
5
5
 
6
- require "lazier"
6
+ # PI: Ignore flog on this file.
7
+
7
8
  require "brauser"
8
- require "interactor"
9
9
  require "addressable/uri"
10
- require "rack/utils"
11
- require "rack/fiber_pool"
12
10
  require "em-synchrony"
13
- require "oj"
11
+ require "rack/utils"
12
+ require "emoji"
13
+ require "action_view/helpers/capture_helper"
14
+ require "action_view/helpers/tag_helper"
14
15
 
15
- Lazier.load!
16
+ Lazier.load!(:hash, :datetime)
16
17
  Oj.default_options = Oj.default_options.merge(mode: :compat, indent: 2, symbol_keys: true)
17
18
 
18
- require "ballast/version" if !defined?(Ballast::Version)
19
19
  require "ballast/errors"
20
- require "ballast/context"
21
- require "ballast/operation"
22
- require "ballast/operations_chain"
20
+ require "ballast/emoji"
21
+ require "ballast/ajax_response"
22
+ require "ballast/service"
23
23
  require "ballast/request_domain_matcher"
24
24
  require "ballast/configuration"
25
- require "ballast/concerns/ajax"
25
+ require "ballast/concerns/ajax_handling"
26
26
  require "ballast/concerns/common"
27
27
  require "ballast/concerns/view"
28
28
  require "ballast/concerns/errors_handling"
29
29
  require "ballast/middlewares/default_host"
30
30
 
31
+ # A collection of base utilities for web frameworks.
31
32
  module Ballast
32
- # If running under eventmachine, run the block in a thread of its threadpool using EM::Synchrony, otherwise run the block normally.
33
+ # If running under eventmachine, runs the block in a thread of its threadpool using EM::Synchrony, otherwise runs the block directly.
33
34
  #
34
35
  # @param start_reactor [Boolean] If start a EM::Synchrony reactor if none is running.
35
36
  # @param block [Proc] The block to run.
36
37
  def self.in_em_thread(start_reactor = false, &block)
37
- if EM.reactor_running? then
38
+ if EM.reactor_running?
38
39
  run_in_thread(&block)
39
- elsif start_reactor then
40
+ elsif start_reactor
40
41
  EM.synchrony do
41
42
  Ballast.in_em_thread(&block)
42
43
  EM.stop
@@ -47,12 +48,11 @@ module Ballast
47
48
  end
48
49
 
49
50
  private
50
- # Runs a block inside a EM thread.
51
- #
52
- # @param block [Proc] The block to run.
53
- def self.run_in_thread(&block)
54
- EM::Synchrony.defer do
55
- Fiber.new { block.call }.resume
56
- end
51
+
52
+ # :nodoc:
53
+ def self.run_in_thread(&block)
54
+ EM::Synchrony.defer do
55
+ Fiber.new { block.call }.resume
57
56
  end
58
- end
57
+ end
58
+ end
@@ -0,0 +1,61 @@
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 "spec_helper"
7
+
8
+ describe Ballast::AjaxResponse do
9
+ describe "#initialize" do
10
+ it "should save arguments" do
11
+ subject = Ballast::AjaxResponse.new(status: "STATUS", data: "DATA", error: "ERROR", transport: "TRANSPORT")
12
+
13
+ expect(subject.status).to eq("STATUS")
14
+ expect(subject.data).to eq("DATA")
15
+ expect(subject.error).to eq("ERROR")
16
+ expect(subject.transport).to eq("TRANSPORT")
17
+ end
18
+ end
19
+
20
+ describe "#numeric_status" do
21
+ it "should return the status as an integer" do
22
+ expect(Ballast::AjaxResponse.new.numeric_status).to eq(200)
23
+ expect(Ballast::AjaxResponse.new(status: :forbidden).numeric_status).to eq(403)
24
+ expect(Ballast::AjaxResponse.new(status: :whatever).numeric_status).to eq(500)
25
+ end
26
+ end
27
+
28
+ describe "#as_json" do
29
+ it "should serialize correctly" do
30
+ subject = Ballast::AjaxResponse.new(data: "DATA", error: "ERROR", transport: "TRANSPORT")
31
+ expect(subject.as_json).to eq({status: 200, data: "DATA", error: "ERROR"})
32
+ expect(subject.as_json(original_status: true)).to eq({status: :ok, data: "DATA", error: "ERROR"})
33
+ end
34
+ end
35
+
36
+ describe "#reply" do
37
+ before(:example) do
38
+ @transport = OpenStruct.new(request: OpenStruct.new(format: :json), params: {}, performed?: false)
39
+ end
40
+
41
+ subject { Ballast::AjaxResponse.new(status: 200, data: "DATA", error: "ERROR", transport: @transport) }
42
+
43
+ it "should setup the right content type for text" do
44
+ expect(@transport).to receive(:render).with(text: "{\"status\":200,\"data\":\"DATA\",\"error\":\"ERROR\"}", status: 200, callback: nil, content_type: "text/plain")
45
+ subject.reply(format: :text)
46
+ end
47
+
48
+ it "should set the right callback for JSONP" do
49
+ @transport.params[:callback] = "callback"
50
+ expect(@transport).to receive(:render).with(jsonp: "{\"status\":200,\"data\":\"DATA\",\"error\":\"ERROR\"}", status: 200, callback: "callback", content_type: nil)
51
+ subject.reply(format: :jsonp)
52
+ end
53
+
54
+ it "should fallback to transport request format" do
55
+ subject.status = 403
56
+
57
+ expect(@transport).to receive(:render).with(json: "{\"status\":403,\"data\":\"DATA\",\"error\":\"ERROR\"}", status: 403, callback: nil, content_type: nil)
58
+ subject.reply(format: nil)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,86 @@
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 "spec_helper"
7
+
8
+ describe Ballast::Concerns::AjaxHandling do
9
+ class AjaxMockClass < OpenStruct
10
+ include Ballast::Concerns::AjaxHandling
11
+ end
12
+
13
+ subject{ AjaxMockClass.new(response: OpenStruct.new(headers: {}), headers: {}, params: {}, performed?: false) }
14
+
15
+ describe "#ajax_request?" do
16
+ it "should return false by default" do
17
+ expect(AjaxMockClass.new(request: {}, params: {}).ajax_request?).to be_falsey
18
+ end
19
+
20
+ it "should return true when the request is XHR" do
21
+ expect(AjaxMockClass.new(request: OpenStruct.new(xhr?: true)).ajax_request?).to be_truthy
22
+ end
23
+
24
+ it "should return true when the parameter is overriden" do
25
+ expect(AjaxMockClass.new(params: {xhr: true}).ajax_request?).to be_truthy
26
+ end
27
+ end
28
+
29
+ describe "#prepare_ajax_response" do
30
+ it "should return a AJAX response" do
31
+ expect(subject.prepare_ajax_response).to be_a(Ballast::AjaxResponse)
32
+
33
+ expect(Ballast::AjaxResponse).to receive(:new).with({status: "STATUS", data: "DATA", error: "ERROR", transport: subject})
34
+ subject.prepare_ajax_response(status: "STATUS", data: "DATA", error: "ERROR")
35
+ end
36
+ end
37
+
38
+ describe "#prevent_caching" do
39
+ it "should append correct headers" do
40
+ subject.prevent_caching
41
+
42
+ expect(subject.response.headers).to eq({
43
+ "Cache-Control" => "no-cache, no-store, max-age=0, must-revalidate",
44
+ "Pragma" => "no-cache",
45
+ "Expires" => "Fri, 01 Jan 1990 00:00:00 GMT"
46
+ })
47
+ end
48
+ end
49
+
50
+ describe "#allow_cors" do
51
+ it "should append correct headers" do
52
+ subject.allow_cors
53
+
54
+ expect(subject.headers).to eq({
55
+ "Access-Control-Allow-Origin" => "*",
56
+ "Access-Control-Allow-Methods" => "POST, GET, OPTIONS",
57
+ "Access-Control-Allow-Headers" => "*",
58
+ "Access-Control-Max-Age" => "31557600"
59
+ })
60
+ end
61
+
62
+ it "should append custom headers values" do
63
+ subject.allow_cors(allow_origin: "ORIGIN", allow_methods: [:first, :second], allow_headers: "_", max_age: 1.day, allow_credentials: true)
64
+
65
+ expect(subject.headers).to eq({
66
+ "Access-Control-Allow-Origin" => "ORIGIN",
67
+ "Access-Control-Allow-Methods" => "FIRST, SECOND",
68
+ "Access-Control-Allow-Headers" => "_",
69
+ "Access-Control-Max-Age" => "86400",
70
+ "Access-Control-Allow-Credentials" => "true"
71
+ })
72
+ end
73
+ end
74
+
75
+ describe "#generate_robots_txt" do
76
+ it "should generate a robots.txt file which prevents everything by default" do
77
+ expect(subject).to receive(:render).with(text: "User-agent: *\nDisallow: /", content_type: "text/plain")
78
+ subject.disallow_robots
79
+ end
80
+
81
+ it "should generate a robots.txt file which prevents everything by default" do
82
+ expect(subject).to receive(:render).with(text: "User-agent: A\nDisallow: B\nDisallow: C\nDisallow: D\n\nUser-agent: E\nDisallow: F\nDisallow: \nDisallow: G", content_type: "text/plain")
83
+ subject.generate_robots_txt({"A"=> ["B", "C", "D"], "E" => ["F", "", "G"]})
84
+ end
85
+ end
86
+ end
@@ -10,86 +10,51 @@ describe Ballast::Concerns::Common do
10
10
  include Ballast::Concerns::Common
11
11
  end
12
12
 
13
- class OperationMockClass
14
-
15
- end
16
-
17
- module Actions
18
- module CommonMockClass
19
- class Sub
20
- end
21
- end
22
- end
23
-
24
13
  subject{ CommonMockClass.new(request: OpenStruct.new(headers: {}), headers: {}, params: {}, performed?: false) }
25
14
 
26
- describe "#is_json?" do
15
+ describe "#json?" do
27
16
  it "should return false by default" do
28
- expect(CommonMockClass.new(request: OpenStruct.new({format: ""}), params: {}).is_json?).to be(false)
17
+ expect(CommonMockClass.new(request: OpenStruct.new({format: ""}), params: {}).json?).to be_falsey
29
18
  end
30
19
 
31
20
  it "should return true when the request is JSON" do
32
- expect(CommonMockClass.new(request: OpenStruct.new(format: "json")).is_json?).to be(true)
21
+ expect(CommonMockClass.new(request: OpenStruct.new(format: "json")).json?).to be_truthy
33
22
  end
34
23
 
35
24
  it "should return true when the parameter is overriden" do
36
- expect(CommonMockClass.new(request: OpenStruct.new({format: ""}), params: {json: true}).is_json?).to be(true)
25
+ expect(CommonMockClass.new(request: OpenStruct.new({format: ""}), params: {json: true}).json?).to be_truthy
37
26
  end
38
27
  end
39
28
 
40
- describe "#sending_data?" do
29
+ describe "#request_data?" do
41
30
  it "should return the current status" do
42
- expect(CommonMockClass.new(request: OpenStruct.new(post?: false, put?: false)).sending_data?).to be(false)
43
- expect(CommonMockClass.new(request: OpenStruct.new(post?: true, put?: false)).sending_data?).to be(true)
44
- expect(CommonMockClass.new(request: OpenStruct.new(post?: false, put?: true)).sending_data?).to be(true)
45
- end
46
- end
47
-
48
- describe "#perform_operation" do
49
- it "should perform the requested operation and memoize it" do
50
- expect(OperationMockClass).to receive(:perform).with("OWNER", a: 1, b: 2).and_return("OPERATION 1")
51
- expect(OperationMockClass).to receive(:perform).with(subject, c: 3, d: 4).and_return("OPERATION 2")
52
-
53
- subject.perform_operation(OperationMockClass, "OWNER", a: 1, b: 2)
54
- expect(subject.instance_variable_get(:@operation)).to eq("OPERATION 1")
55
- subject.perform_operation(OperationMockClass, c: 3, d: 4)
56
- expect(subject.instance_variable_get(:@operation)).to eq("OPERATION 2")
57
- end
58
- end
59
-
60
- describe "#perform_operations_chain" do
61
- it "should perform the requested operation chain and memoize it" do
62
- expect(Ballast::OperationsChain).to receive(:perform).with("OWNER", [:a, :b], a: 1, b: 2).and_return("OPERATION 1")
63
- expect(Ballast::OperationsChain).to receive(:perform).with(subject, [:c, :d], c: 3, d: 4).and_return("OPERATION 2")
64
-
65
- subject.perform_operations_chain([:a, :b], "OWNER", a: 1, b: 2)
66
- expect(subject.instance_variable_get(:@operation)).to eq("OPERATION 1")
67
- subject.perform_operations_chain([:c, :d], c: 3, d: 4)
68
- expect(subject.instance_variable_get(:@operation)).to eq("OPERATION 2")
31
+ expect(CommonMockClass.new(request: OpenStruct.new(post?: false, put?: false)).request_data?).to be_falsey
32
+ expect(CommonMockClass.new(request: OpenStruct.new(post?: true, put?: false)).request_data?).to be_truthy
33
+ expect(CommonMockClass.new(request: OpenStruct.new(post?: false, put?: true)).request_data?).to be_truthy
69
34
  end
70
35
  end
71
36
 
72
37
  describe "#format_short_duration" do
73
38
  it "should format a date" do
74
39
  now = DateTime.civil(2013, 12, 9, 15, 6, 00)
75
- expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 16, 6, 0), now, "ago")).to eq("now")
76
- expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 15, 5, 58), now, "")).to eq("2s")
77
- expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 15, 3, 0), now, " in the past")).to eq("3m in the past")
78
- expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 8, 6, 0), now, "")).to eq("7h")
79
- expect(subject.format_short_duration(DateTime.civil(2013, 5, 3, 15, 6, 0), now, "")).to eq("May 03")
80
- expect(subject.format_short_duration(DateTime.civil(2011, 6, 4, 15, 6, 0), now, "")).to eq("Jun 04 2011")
40
+ expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 16, 6, 0), reference: now, suffix: "ago")).to eq("now")
41
+ expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 15, 5, 58), reference: now, suffix: "")).to eq("2s")
42
+ expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 15, 3, 0), reference: now, suffix: " in the past")).to eq("3m in the past")
43
+ expect(subject.format_short_duration(DateTime.civil(2013, 12, 9, 8, 6, 0), reference: now, suffix: "")).to eq("7h")
44
+ expect(subject.format_short_duration(DateTime.civil(2013, 5, 3, 15, 6, 0), reference: now, suffix: "")).to eq("May 03")
45
+ expect(subject.format_short_duration(DateTime.civil(2011, 6, 4, 15, 6, 0), reference: now, suffix: "")).to eq("Jun 04 2011")
81
46
  end
82
47
  end
83
48
 
84
49
  describe "#format_long_date" do
85
- before(:each) do
50
+ before(:example) do
86
51
  expect_any_instance_of(DateTime).to receive(:dst?).and_return(true)
87
52
  expect(Time).to receive(:zone).at_least(1).and_return(ActiveSupport::TimeZone["UTC"], ActiveSupport::TimeZone["Pacific Time (US & Canada)"])
88
53
  end
89
54
 
90
55
  it "should format a date" do
91
56
  expect(subject.format_long_date(DateTime.civil(2013, 7, 11, 10, 9, 8))).to eq("10:09AM • Jul 11th, 2013 (UTC)")
92
- expect(subject.format_long_date(DateTime.civil(2013, 7, 11, 10, 9, 8), "SEP", "%F %T %o %- %:Z")).to eq("2013-07-11 10:09:08 11th SEP Pacific Time (US & Canada) (DST)")
57
+ expect(subject.format_long_date(DateTime.civil(2013, 7, 11, 10, 9, 8), separator: "SEP", format: "%F %T %o %- %:Z")).to eq("2013-07-11 10:09:08 11th SEP Pacific Time (US & Canada) (DST)")
93
58
  end
94
59
  end
95
60
 
@@ -114,7 +79,7 @@ describe Ballast::Concerns::Common do
114
79
  expect(subject).to receive(:authenticate_with_http_basic).and_return(false)
115
80
  expect(subject).to receive(:handle_error).with({status: 401, title: "TITLE", message: "MESSAGE"})
116
81
 
117
- subject.authenticate_user("AREA", "TITLE", "MESSAGE")
82
+ subject.authenticate_user(area: "AREA", title: "TITLE", message: "MESSAGE")
118
83
  expect(subject.headers["WWW-Authenticate"]).to eq("Basic realm=\"AREA\"")
119
84
  end
120
85
  end
@@ -6,65 +6,71 @@
6
6
  require "spec_helper"
7
7
 
8
8
  describe Ballast::Concerns::ErrorsHandling do
9
- class ErrorsHandlingMockClass < OpenStruct
10
- include Ballast::Concerns::Ajax
9
+ class ErrorsHandlingMockClass
10
+ include Ballast::Concerns::AjaxHandling
11
11
  include Ballast::Concerns::ErrorsHandling
12
12
 
13
- def initialize(attrs)
14
- @operation = OpenStruct.new(attrs.delete(:operation))
15
- super(attrs)
13
+ def request
14
+ OpenStruct.new(format: "json")
15
+ end
16
+
17
+ def performed?
18
+
19
+ end
20
+
21
+ def render(*args)
22
+
16
23
  end
17
24
  end
18
25
 
19
- subject{ ErrorsHandlingMockClass.new(response: OpenStruct.new(headers: {}), headers: {}, params: {}, performed?: false) }
26
+ subject{ ErrorsHandlingMockClass.new }
20
27
 
21
28
  describe "#handle_error" do
22
29
  it "should handle a custom error" do
23
- error = {status: "STATUS", error: "ERROR"}
30
+ error = {status: "STATUS", error: "ERROR", title: "TITLE"}
24
31
  expect(subject).to receive(:send_or_render_error).with("LAYOUT", nil)
25
- subject.handle_error(error, "LAYOUT", "TITLE")
26
-
32
+ subject.handle_error(error, layout: "LAYOUT", title: "OTHER TITLE")
27
33
  expect(subject.instance_variable_get(:@error)).to eq(error)
28
- expect(subject.instance_variable_get(:@error_code)).to eq("STATUS")
29
- expect(subject.instance_variable_get(:@error_title)).to eq("TITLE")
30
- expect(subject.instance_variable_get(:@error_message)).to eq("ERROR")
34
+
35
+ error = {status: "STATUS", error: "ERROR"}
36
+ expect(subject).to receive(:send_or_render_error).with("LAYOUT", nil)
37
+ subject.handle_error(error, layout: "LAYOUT", title: "OTHER TITLE")
38
+ expect(subject.instance_variable_get(:@error)).to eq(error.merge({title: "OTHER TITLE"}))
31
39
  end
32
40
 
33
41
  it "should handle a debug error" do
42
+ error = Lazier::Exceptions::Debug.new("MESSAGE")
34
43
  expect(subject).to receive(:send_or_render_error)
35
- subject.handle_error(Lazier::Exceptions::Debug.new("MESSAGE"))
36
44
 
37
- expect(subject.instance_variable_get(:@error_code)).to eq(503)
38
- expect(subject.instance_variable_get(:@error_title)).to eq("Debug")
39
- expect(subject.instance_variable_get(:@error_message)).to be_nil
45
+ subject.handle_error(error)
46
+ expect(subject.instance_variable_get(:@error)).to eq({status: 503, title: "Debug", error: "MESSAGE", exception: error})
40
47
  end
41
48
 
42
49
  it "should handle every other error" do
50
+ error = RuntimeError.new("ERROR")
43
51
  expect(subject).to receive(:send_or_render_error)
44
- subject.handle_error(RuntimeError.new("ERROR"))
45
52
 
46
- expect(subject.instance_variable_get(:@error_code)).to eq(500)
47
- expect(subject.instance_variable_get(:@error_title)).to eq("Error - RuntimeError")
48
- expect(subject.instance_variable_get(:@error_message)).to be_nil
53
+ subject.handle_error(error)
54
+ expect(subject.instance_variable_get(:@error)).to eq({status: 500, title: "Error - RuntimeError", error: "ERROR", exception: error})
49
55
  end
50
56
 
51
57
  it "should render an AJAX error" do
52
58
  expect_any_instance_of(RuntimeError).to receive(:backtrace).and_return(["A", "B"])
53
- allow(subject).to receive(:request).and_return(OpenStruct.new(format: :json))
54
- expect(subject).to receive(:is_ajax?).exactly(2).and_return(true, false)
55
-
56
- expect(subject).to receive(:send_ajax).with({status: 500, error: "ERROR", data: {type: "Error - RuntimeError", backtrace: ["A", "B"]}}.with_indifferent_access, {format: :json})
57
- expect(subject).to receive(:send_ajax).with({status: :forbidden, error: "ERROR", data: {type: "TITLE"}}.with_indifferent_access, {format: :json})
59
+ expect(subject).to receive(:ajax_request?).exactly(2).and_return(true, false)
60
+
61
+ expect(Ballast::AjaxResponse).to receive(:new).with({status: 500, error: "ERROR", data: {description: "Error - RuntimeError", backtrace: ["A", "B"]}, transport: subject}).and_call_original
62
+ expect(Ballast::AjaxResponse).to receive(:new).with({status: :forbidden, error: "ERROR", data: {description: "TITLE", backtrace: nil}, transport: subject}).and_call_original
58
63
 
59
- subject.handle_error(RuntimeError.new("ERROR"), "LAYOUT")
64
+ subject.handle_error(RuntimeError.new("ERROR"))
60
65
  subject.instance_variable_set(:@error, nil)
61
- subject.handle_error({title: "TITLE", status: :forbidden, error: "ERROR"}, :json)
66
+ subject.handle_error({title: "TITLE", status: :forbidden, error: "ERROR"}, format: :json)
62
67
  end
63
68
 
64
69
  it "should render a HTML error" do
65
- allow(subject).to receive(:request).and_return(OpenStruct.new(format: :html))
70
+ expect(subject).to receive(:ajax_request?).and_return(false)
71
+ expect(subject).to receive(:request).and_return(OpenStruct.new(format: "HTML"))
66
72
  expect(subject).to receive(:render).with(html: "", status: 500, layout: "LAYOUT", formats: [:html])
67
- subject.handle_error(RuntimeError.new("ERROR"), "LAYOUT")
73
+ subject.handle_error(RuntimeError.new("ERROR"), layout: "LAYOUT")
68
74
  end
69
75
  end
70
76
  end