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,73 @@
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 AjaxHandling
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 ajax_request?
17
+ request.safe_send(:xhr?).to_boolean || 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] The data of the response.
24
+ # @param error [Object|NilClass] The error of the response.
25
+ def prepare_ajax_response(status: :ok, data: {}, error: nil)
26
+ Ballast::AjaxResponse.new(status: status, data: data, error: error, transport: self)
27
+ end
28
+
29
+ # Prevents HTTP caching.
30
+ def prevent_caching
31
+ response.headers.merge!({
32
+ "Cache-Control" => "no-cache, no-store, max-age=0, must-revalidate",
33
+ "Pragma" => "no-cache",
34
+ "Expires" => "Fri, 01 Jan 1990 00:00:00 GMT"
35
+ })
36
+ end
37
+
38
+ # Allows HTTP Cross-Origin Resource Sharing.
39
+ #
40
+ # @param allow_origin [String] The value for the `Access-Control-Allow-Origin` header.
41
+ # @param allow_methods [Array] A list of methods for the `Access-Control-Allow-Methods` header.
42
+ # @param allow_headers [String] The value for the `Access-Control-Allow-Headers` header.
43
+ # @param max_age [Float|Fixnum] The value for the `Access-Control-Max-Age` header.
44
+ # @param allow_credentials [Boolean] The value for the `Access-Control-Allow-Credentials` header.
45
+ def allow_cors(allow_origin: "*", allow_methods: [:post, :get, :options], allow_headers: "*", max_age: 1.year, allow_credentials: false)
46
+ headers.merge!({
47
+ "Access-Control-Allow-Origin" => allow_origin,
48
+ "Access-Control-Allow-Methods" => allow_methods.map { |m| m.to_s.upcase }.join(", "),
49
+ "Access-Control-Allow-Headers" => allow_headers,
50
+ "Access-Control-Max-Age" => max_age.to_i.to_s
51
+ })
52
+
53
+ headers["Access-Control-Allow-Credentials"] = "true" if allow_credentials
54
+ end
55
+
56
+ # Generates a `robots.txt file.
57
+ #
58
+ # @param configuration [Hash|NilClass] An hash of agent and list of paths to include.
59
+ def generate_robots_txt(configuration = nil)
60
+ configuration ||= {"*" => "/"}
61
+ rv = configuration.reduce([]) { |accu, (agent, paths)|
62
+ paths = paths.ensure_array.map { |e| "Disallow: #{e}" }
63
+
64
+ accu << "User-agent: #{agent}\n#{paths.join("\n")}"
65
+ accu
66
+ }.join("\n\n")
67
+
68
+ render(text: rv, content_type: "text/plain")
69
+ end
70
+ alias_method :disallow_robots, :generate_robots_txt
71
+ end
72
+ end
73
+ end
@@ -9,53 +9,32 @@ module Ballast
9
9
  module Common
10
10
  # Checks if the current request wants JSON or JSONP as response.
11
11
  #
12
- # @return [Boolean] `true` if the request is JSON, `false` otherwise.
13
- def is_json?
14
- ([:json, :jsonp].include?(request.format.to_sym) || params[:json].to_boolean) ? true : false
12
+ # @return [Boolean] `true` if the request is JSON(P), `false` otherwise.
13
+ def json?
14
+ [:json, :jsonp].include?(request.format.to_sym) || params[:json].to_boolean
15
15
  end
16
16
 
17
17
  # Checks if the user is sending any data.
18
18
  #
19
19
  # @return [Boolean] `true` if the user is sending data, `false` otherwise.
20
- def sending_data?
21
- request.post? || request.put?
22
- end
23
-
24
- # Performs an operation, using itself as owner by default.
25
- #
26
- # @param klass [Class] The operation to perform.
27
- # @param owner [Object] The owner to use. By default it uses itself.
28
- # @param kwargs [Hash] The arguments for performing.
29
- # @return [Operation] The performed operation.
30
- def perform_operation(klass, owner = nil, **kwargs)
31
- @operation = klass.perform(owner || self, **kwargs)
32
- end
33
-
34
- # Performs an operations chain, using itself as owner by default.
35
- #
36
- # @param klasses [Array] The operations to perform.
37
- # @param owner [Object] The owner to use. By default it uses itself.
38
- # @param kwargs [Hash] The arguments for performing.
39
- # @return [OperationChain] The performed operation chain.
40
- def perform_operations_chain(klasses, owner = nil, **kwargs)
41
- @operation = Ballast::OperationsChain.perform(owner || self, klasses, **kwargs)
20
+ def request_data?
21
+ request.post? || request.put? || request.patch?
42
22
  end
43
23
 
44
24
  # Formats a relative date using abbreviation or short formats.
45
25
  #
46
26
  # @param date [DateTime] The date to format.
47
- # @param reference [DateTime] The reference date.
27
+ # @param reference [DateTime|NilClass] The reference date.
48
28
  # @param suffix [String] The suffix to add to the formatted date.
49
29
  # @return [String] The formatted date.
50
- def format_short_duration(date, reference = nil, suffix = "")
51
- reference ||= Time.now
52
- amount = (reference.to_i - date.to_i).to_i
30
+ def format_short_duration(date, reference: nil, suffix: "")
31
+ amount = (reference || Time.now).to_i - date.to_i
53
32
 
54
- if amount <= 0 then
33
+ if amount <= 0
55
34
  "now"
56
- elsif amount < 1.day then
35
+ elsif amount < 1.day
57
36
  format_short_amount(amount, suffix)
58
- elsif amount < 1.year then
37
+ elsif amount < 1.year
59
38
  date.strftime("%b %d")
60
39
  else
61
40
  date.strftime("%b %d %Y")
@@ -68,9 +47,9 @@ module Ballast
68
47
  # @param suffix [String] The suffix to add to the formatted amount.
69
48
  # @return [String] The formatted amount.
70
49
  def format_short_amount(amount, suffix = "")
71
- if amount < 1.minute then
50
+ if amount < 1.minute
72
51
  "#{amount.floor}s#{suffix}"
73
- elsif amount < 1.hour then
52
+ elsif amount < 1.hour
74
53
  "#{(amount / 60).floor}m#{suffix}"
75
54
  else
76
55
  "#{(amount / 3600).floor}h#{suffix}"
@@ -83,29 +62,28 @@ module Ballast
83
62
  # @param separator [String] The separator between date and time.
84
63
  # @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
85
64
  # and `%:Z` for the zone name considering also DST.
86
- def format_long_date(date, separator = "•", format = "%I:%M%p %- %b %o, %Y (%:Z)")
65
+ def format_long_date(date, separator: "•", format: "%I:%M%p %- %b %o, %Y (%:Z)")
87
66
  tz = Time.zone
88
- replacements = {"%-" => separator, "%o" => date.day.ordinalize, "%:Z" => tz.send(tz.uses_dst? && date.dst? ? :dst_name : :name)}
89
- date.strftime(format).gsub(/%(-|o|(:Z))/) {|r| replacements.fetch(r, r) }
67
+ replacements = {"%-" => separator, "%o" => date.day.ordinalize, "%:Z" => tz.current_name(tz.uses_dst? && date.dst?)}
68
+ date.strftime(format).gsub(/%(-|o|(:Z))/) { |r| replacements.fetch(r, r) }
90
69
  end
91
70
 
92
71
  # Authenticates a user via HTTP, handling the error if the authentication failed.
93
72
  #
94
- # @param area [String] The name of the area.
95
- # @param title [String] A title for authentication errors.
96
- # @param message [String] A message for authentication errors.
73
+ # @param area [String|NilClass] The name of the area.
74
+ # @param title [String|NilClass] A title for authentication errors.
75
+ # @param message [String|NilClass] A message for authentication errors.
97
76
  # @param authenticator [Proc] A block to verify if authentication is valid.
98
- def authenticate_user(area = nil, title = nil, message = nil, &authenticator)
77
+ def authenticate_user(area: nil, title: nil, message: nil, &authenticator)
78
+ return if authenticate_with_http_basic { |username, password| authenticator.call(username, password) }
79
+
99
80
  area ||= "Private Area"
100
81
  title ||= "Authentication required."
101
82
  message ||= "To view this resource you have to authenticate."
102
- authenticated = authenticate_with_http_basic { |username, password| authenticator.call(username, password) }
103
83
 
104
- if !authenticated then
105
- headers["WWW-Authenticate"] = "Basic realm=\"#{area}\""
106
- handle_error({status: 401, title: title, message: message})
107
- end
84
+ headers["WWW-Authenticate"] = "Basic realm=\"#{area}\""
85
+ handle_error({status: 401, title: title, message: message})
108
86
  end
109
87
  end
110
88
  end
111
- end
89
+ end
@@ -12,44 +12,35 @@ module Ballast
12
12
  # Handles an error in the application.
13
13
  #
14
14
  # @param exception [Hash|Exception] The exception to handle.
15
- # @param layout [String] The layout to use to render the error.
15
+ # @param layout [String] The layout to use to render the error. The `@error` variable will be exposed.
16
16
  # @param title [String] The title to set in case of custom errors.
17
- # @param format [String|Symbol] The format of the response.
18
- def handle_error(exception = nil, layout = "error", title = "Error - Application", format = nil)
19
- @error ||= exception
20
-
21
- if @error.is_a?(Lazier::Exceptions::Debug) then
22
- @error_title = "Debug"
23
- @error_code = 503
24
- elsif @error.is_a?(Hash) then
25
- @error_title = @error[:title] || title
26
- @error_code = @error[:status]
27
- @error_message = @error[:error]
28
- else
29
- @error_title = "Error - #{@error.class.to_s}"
30
- @error_code = 500
31
- end
17
+ # @param format [String|Symbol|NilClass] The format of the response.
18
+ def handle_error(exception, layout: "error", title: "Error - Application", format: nil)
19
+ @error =
20
+ if exception.is_a?(Lazier::Exceptions::Debug)
21
+ {status: 503, title: "Debug", error: exception.message, exception: exception}
22
+ elsif exception.is_a?(::Hash)
23
+ exception.reverse_merge({title: title})
24
+ else
25
+ {status: 500, title: "Error - #{exception.class}", error: exception.message, exception: exception}
26
+ end
32
27
 
33
28
  send_or_render_error(layout, format)
34
29
  end
35
30
 
36
31
  private
37
- # Send an AJAX error o renders it.
38
- #
39
- # @param layout [String] The layout to use to render the error.
40
- # @param format [String|Symbol] The format of the response.
41
- def send_or_render_error(layout, format = nil)
42
- format ||= request.format.to_sym
43
32
 
44
- if is_ajax? || format.to_s =~ /^json/ then
45
- details = {type: @error_title}
46
- details[:backtrace] = @error.backtrace if @error.respond_to?(:backtrace)
47
- data = prepare_ajax(@error_code, details, @error_message || @error.message)
48
- send_ajax(data, format: format)
49
- else
50
- render(html: "", status: @error_code, layout: layout, formats: [:html])
51
- end
33
+ # :nodoc:
34
+ def send_or_render_error(layout, format = nil)
35
+ format ||= request.format.to_sym
36
+
37
+ if ajax_request? || format.match(/^json/)
38
+ details = {description: @error[:title], backtrace: @error[:exception].safe_send(:backtrace)}
39
+ prepare_ajax_response(status: @error[:status], data: details, error: @error[:error]).reply(format: format)
40
+ else
41
+ render(html: "", status: @error[:status], layout: layout, formats: [:html])
52
42
  end
43
+ end
53
44
  end
54
45
  end
55
46
  end
@@ -11,30 +11,30 @@ module Ballast
11
11
  #
12
12
  # @return [String] The scoped string.
13
13
  def scope_css
14
- "%s %s" % [controller_path.gsub("/", "-"), action_name]
14
+ format("%s %s", controller_path.gsub("/", "-"), action_name)
15
15
  end
16
16
 
17
17
  # Returns an instance of the browser.
18
18
  #
19
19
  # @return [Browser] A browser object.
20
20
  def browser
21
- @browser ||= Brauser::Browser.new(request.user_agent)
21
+ @browser ||= Brauser::Browser.new(request.user_agent, request.headers["Accept-Language"])
22
22
  end
23
23
 
24
24
  # Checks if the current browser is supported according to a definition YAML file.
25
25
  #
26
- # @param conf_file [String] The configuration file which holds the definitions.
26
+ # @param file [String] The configuration file which holds the definitions.
27
+ # @param root [String|NilClass] The directory that contains the configuration file.
27
28
  # @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)
29
+ def browser_supported?(file = "config/supported-browsers.yml", root: nil)
30
+ browser.supported?(((Ballast::Configuration.default_root || root) + "/" + file).to_s)
31
31
  end
32
32
 
33
33
  # Returns one or all layout parameters.
34
34
  #
35
35
  # @param key [String|Symbol|NilClass] The parameter to return. If set to `nil`, all the parameters will be returned as an hash.
36
- # @param default_value [Object] The default value if the parameter is not present.
37
- # @return [Object|Hash] The parameter or the entire layout parameters hash.
36
+ # @param default_value [Object|NilClass] The default value if the parameter is not present.
37
+ # @return [Object|Hash|NilClass] The parameter or the entire layout parameters hash.
38
38
  def layout_params(key = nil, default_value = nil)
39
39
  initialize_view_params
40
40
  key ? @layout_params.fetch(key, default_value) : @layout_params
@@ -43,8 +43,8 @@ module Ballast
43
43
 
44
44
  # Adds/Replaces layout parameters.
45
45
  #
46
- # @param args [Hash] The new parameters to add.
47
- def set_layout_params(**args)
46
+ # @param args [Hash] The parameters to add or replace.
47
+ def update_layout_params(**args)
48
48
  initialize_view_params
49
49
  @layout_params.merge!(args)
50
50
  end
@@ -53,18 +53,19 @@ module Ballast
53
53
  #
54
54
  # @param id [String|NilClass|FalseClass] The id for the tag. If `nil` or `false`, the parameters will be returned as an hash.
55
55
  # @param tag [Symbol] The tag to use for HTML.
56
- # @return [String|Hash] Javascript parameters as HTML or the hash.
57
- def javascript_params(id = nil, tag = :details)
56
+ # @param attribute [Symbol] The attribute to use for the HTML element id.
57
+ # @return [String|Hash] Javascript parameters as HTML or as an hash.
58
+ def javascript_params(id = nil, tag: :details, attribute: "data-jid")
58
59
  initialize_view_params
59
- id ? content_tag(tag, @javascript_params.to_json.html_safe, "data-jid" => id): @javascript_params
60
+ id ? content_tag(tag, @javascript_params.to_json.html_safe, attribute => id) : @javascript_params
60
61
  end
61
62
 
62
- # Appends new Javascript parameters.
63
+ # Adds/Replaces Javascript parameters.
63
64
  #
64
65
  # @param key [String|Symbol] The key of the new parameters. If `nil`, the root will be merged/replaced.
65
- # @param data [Hash] The data to add.
66
+ # @param data [Hash] The data to add or replace.
66
67
  # @param replace [Boolean] Whether to replace existing data rather than merge.
67
- def add_javascript_params(key, data, replace = false)
68
+ def update_javascript_params(key, data, replace: false)
68
69
  initialize_view_params
69
70
 
70
71
  if key
@@ -79,11 +80,12 @@ module Ballast
79
80
  end
80
81
 
81
82
  private
82
- # Prepares parameters for views.
83
- def initialize_view_params
84
- @layout_params ||= HashWithIndifferentAccess.new
85
- @javascript_params ||= HashWithIndifferentAccess.new
86
- end
83
+
84
+ # :nodoc:
85
+ def initialize_view_params
86
+ @layout_params ||= HashWithIndifferentAccess.new
87
+ @javascript_params ||= HashWithIndifferentAccess.new
88
+ end
87
89
  end
88
90
  end
89
- end
91
+ end
@@ -7,24 +7,44 @@ module Ballast
7
7
  # A class which loads a list of YAML files in a folder and expose them in a dotted notation.
8
8
  # For each file, only the subsection for the current environment is loaded, so each YAML document should be an hash.
9
9
  class Configuration < HashWithIndifferentAccess
10
+ # Returns the default root directory to lookup a configuration. It will be the Rails root if set or the current folder.
11
+ #
12
+ # @return [String] The default root directory to lookup a configuration.
13
+ def self.default_root
14
+ defined?(Rails) ? Rails.root.to_s : Dir.pwd
15
+ end
16
+
17
+ # Returns the default environment. It will be the first non-nil of the following: Rails environment, the Rack environment or "production".
18
+ #
19
+ # @return [String] The default environment.
20
+ def self.default_environment
21
+ defined?(Rails) ? Rails.env : ENV.fetch("RACK_ENV", "production")
22
+ end
23
+
10
24
  # Creates a new configuration.
11
25
  #
12
26
  # @param sections [Array] A list of sections to load. Each section name should be the basename (without extension) of a file in the root folder.
13
27
  # Subfolders are not supported.
14
- # @param root [String] The root folder where look for file. Default is the Rails root.
15
- # @param environment [String] The environment to load. Default is the Rails environment.
16
- def initialize(sections: [], root: nil, environment: nil)
28
+ # @param root [String|NilClass] The root folder where look for file.
29
+ # @param environment [String|NilClass] The environment to load.
30
+ def initialize(*sections, root: nil, environment: nil)
17
31
  super()
18
- root ||= Rails.root.to_s
19
- environment ||= Rails.env
32
+ root ||= ::Ballast::Configuration.default_root
33
+ environment ||= ::Ballast::Configuration.default_environment
20
34
 
21
35
  sections.each do |section|
22
- content = (YAML.load_file("#{root}/config/#{section}.yml") rescue {}).with_indifferent_access
23
- self[section] = content[environment]
24
- self[section.underscore] = self[section] if section.index("-")
36
+ content = load_section(root, section)
37
+ self[section.underscore] = content.fetch(environment, {})
25
38
  end
26
39
 
27
- self.enable_dotted_access
40
+ enable_dotted_access
41
+ end
42
+
43
+ private
44
+
45
+ # :nodoc:
46
+ def load_section(root, section)
47
+ YAML.load_file("#{root}/config/#{section}.yml") rescue {}
28
48
  end
29
49
  end
30
- end
50
+ end
@@ -0,0 +1,114 @@
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 module to ease emoji handling.
8
+ module Emoji
9
+ # General utility methods.
10
+ #
11
+ # @attribute url_mapper
12
+ # @return [Proc] The current URL mapper or a default one (which will return the relative URL unmodified).
13
+ module Utils
14
+ attr_accessor :url_mapper
15
+
16
+ # Returns the regular expression which matches all the known emojis.
17
+ #
18
+ # @return [Regexp] The regular expression which matches all the known emojis.
19
+ def replace_regex
20
+ @replace_regex ||= /(#{::Emoji.send(:unicodes_index).keys.join("|")})/
21
+ end
22
+
23
+ # Replaces all the emojis in the text using the requested mod.
24
+ #
25
+ # @param text [String] The text to manipulate.
26
+ # @param mode [Symbol] The method to use when replacing icons.
27
+ # @param options [Hash] The options to pass to the replacing method.
28
+ # @return [String] The text with all emojis replaced.
29
+ def replace(text, mode: :html, **options)
30
+ mode = :markup unless mode && ::Emoji::Character.new(nil).respond_to?(mode)
31
+ text.ensure_string.gsub(replace_regex) { invoke(::Emoji.find_by_unicode(Regexp.last_match[1]), mode, options) }
32
+ end
33
+
34
+ # Lists all the emoji known in a hash.
35
+ #
36
+ # @param keys_method [Symbol] The method to use for keys.
37
+ # @param values_method [Symbol] The method to use for values.
38
+ # @param options [Hash] The options to pass to all methods.
39
+ # @return [Hash] A hash of all known emojis.
40
+ def enumerate(keys_method: :markup, values_method: :html, **options)
41
+ tester = ::Emoji::Character.new(nil)
42
+ keys_method = :markup unless keys_method && tester.respond_to?(keys_method)
43
+ values_method = :html unless values_method && tester.respond_to?(values_method)
44
+
45
+ ::Emoji.all.reduce({}) { |accu, icon|
46
+ accu[invoke(icon, keys_method, options)] = invoke(icon, values_method, options)
47
+ accu
48
+ }
49
+ end
50
+
51
+ # Returns the URL mapper for the emojis.
52
+ #
53
+ # @return [Proc] The current URL mapper or a default one (which will return the relative URL unmodified).
54
+ def url_mapper
55
+ @url_mapper || ->(url) { url }
56
+ end
57
+
58
+ # Returns a absolute URL for a emoji image.
59
+ #
60
+ # @param image [String] The relative URL of the emoji filename.
61
+ # @return [String] The absolute URL of the emoji filename.
62
+ def url_for(image)
63
+ url_mapper.call(image)
64
+ end
65
+
66
+ private
67
+
68
+ # :nodoc:
69
+ def invoke(subject, method, options)
70
+ subject.method(method).arity == 1 ? subject.send(method, options) : subject.send(method)
71
+ end
72
+ end
73
+
74
+ # Extensions for a emoji character.
75
+ module Character
76
+ include ActionView::Helpers::TagHelper
77
+ include ActiveSupport::Concern
78
+
79
+ # Returns a markup for the current character.
80
+ #
81
+ # @return [String] The markup for a character.
82
+ def markup
83
+ ":#{name}:"
84
+ end
85
+
86
+ # Returns a image URL for the current character.
87
+ #
88
+ # @return [String] The image URL for the current character.
89
+ def url
90
+ ::Emoji.url_for(image_filename)
91
+ end
92
+
93
+ # Returns a image tag for the current character.
94
+ # @see ActionView::Helpers::TagHelper#tag
95
+ #
96
+ # @return [String] The options for the tag generation.
97
+ def image_tag(options = {})
98
+ options = options.reverse_merge({alt: markup, title: markup, rel: "tooltip"})
99
+ classes = options[:class].ensure_string.tokenize(pattern: /[\s,]+/, no_duplicates: true)
100
+ classes << "emoji" unless classes.include?("emoji")
101
+
102
+ options[:src] = url
103
+ options[:class] = classes.uniq.join(" ")
104
+
105
+ tag(:img, options)
106
+ end
107
+ alias_method :image, :url
108
+ alias_method :html, :image_tag
109
+ end
110
+ end
111
+ end
112
+
113
+ ::Emoji.extend(Ballast::Emoji::Utils)
114
+ ::Emoji::Character.include(Ballast::Emoji::Character)
@@ -8,27 +8,30 @@ module Ballast
8
8
  module Errors
9
9
  # The base error raised from an application.
10
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
11
+ # @attribute [r] details
12
+ # @return [String|Hash|NilClass] The details of the error. If a Hash, it should contain the keys `status` and `error`.
13
+ class Base < RuntimeError
14
+ attr_reader :details
15
15
 
16
- def initialize(msg = nil)
17
- super(msg)
18
- @response = msg
16
+ # Creates a new error.
17
+ #
18
+ # @param details [String|Hash|NilClass] The details of this error.
19
+ def initialize(details = nil)
20
+ super("")
21
+ @details = details
19
22
  end
20
23
  end
21
24
 
22
25
  # This is raised when an invalid domain is requested.
23
- class InvalidDomain < BaseError
26
+ class InvalidDomain < Base
24
27
  end
25
28
 
26
- # This is raised when something went wrong during the processing of a operation.
27
- class PerformError < BaseError
29
+ # This is raised when something went wrong during the processing of a operation or a service.
30
+ class Failure < Base
28
31
  end
29
32
 
30
- # This is raised when some invalid parameters are passed to a operation.
31
- class ValidationError < BaseError
33
+ # This is raised when some invalid parameters are passed to a operation or a service.
34
+ class ValidationFailure < Failure
32
35
  end
33
36
  end
34
- end
37
+ end
@@ -22,9 +22,9 @@ module Ballast
22
22
  # @param env [Hash] A Rack environment.
23
23
  def call(env)
24
24
  old_host = env["SERVER_NAME"].ensure_string
25
- new_host = @hosts[ENV["RACK_ENV"]]
25
+ new_host = @hosts[ENV.fetch("RACK_ENV", "production")]
26
26
 
27
- if old_host =~ /^\d/ && new_host then
27
+ if old_host =~ /^\d/ && new_host
28
28
  env["ORIG_SERVER_NAME"] = old_host
29
29
  env["ORIG_HTTP_HOST"] = env["HTTP_HOST"].dup
30
30
  env["SERVER_NAME"] = new_host
@@ -35,4 +35,4 @@ module Ballast
35
35
  end
36
36
  end
37
37
  end
38
- end
38
+ end
@@ -9,20 +9,20 @@ module Ballast
9
9
  # @attribute domains
10
10
  # @return [Array] The list of domains which mark a positive match.
11
11
  # @attribute replace_pattern
12
- # @return [String|Regexp] A optional pattern to replace in the request host. See `String#gsub`.
12
+ # @return [String|Regexp] A optional pattern to manipulate the request host before trying the match. See `String#gsub`.
13
13
  # @attribute replace_string
14
- # @return [String] A string to use for replacement in the request host. See `String#gsub`.
14
+ # @return [String] A string to manipulate the request host before trying the match. See `String#gsub`.
15
15
  # @attribute replace_block
16
- # @return [Proc] A block to use for replacement in the request host. See `String#gsub`.
16
+ # @return [Proc] A block to use to manipulate the request host before trying the match. See `String#gsub`.
17
17
  class RequestDomainMatcher
18
18
  attr_accessor :domains, :replace_pattern, :replace_string, :replace_block
19
19
 
20
20
  # Creates a new matcher.
21
21
  #
22
22
  # @param domains [String|Array] The list of domains which mark a positive match.
23
- # @param replace_pattern [String|Regexp] A optional pattern to replace in the request host. See `String#gsub`.
24
- # @param replace_string [String] A string to use for replacement in the request host. See `String#gsub`.
25
- # @param replace_block [Proc] A block to use for replacement in the request host. See `String#gsub`.
23
+ # @param replace_pattern [String|Regexp] A optional pattern to manipulate the request host before trying the match. See `String#gsub`.
24
+ # @param replace_string [String] A string to manipulate the request host before trying the match. See `String#gsub`.
25
+ # @param replace_block [Proc] A block to use to manipulate the request host before trying the match. See `String#gsub`.
26
26
  def initialize(domains, replace_pattern = /\.dev$/, replace_string = "", &replace_block)
27
27
  @domains = domains.ensure_array
28
28
  @replace_pattern = replace_pattern
@@ -39,4 +39,4 @@ module Ballast
39
39
  @domains.include?(final_host)
40
40
  end
41
41
  end
42
- end
42
+ end