howitzer 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +32 -0
  4. data/.travis.yml +1 -4
  5. data/.yardopts +1 -2
  6. data/CHANGELOG.md +28 -1
  7. data/Gemfile +6 -0
  8. data/LICENSE +1 -1
  9. data/README.md +55 -85
  10. data/Rakefile +7 -7
  11. data/bin/howitzer +56 -31
  12. data/features/cli_new.feature +162 -79
  13. data/features/cli_update.feature +114 -21
  14. data/features/step_definitions/common_steps.rb +29 -9
  15. data/features/support/env.rb +1 -1
  16. data/features/support/transformers.rb +2 -2
  17. data/generators/base_generator.rb +121 -49
  18. data/generators/config/config_generator.rb +8 -5
  19. data/generators/config/templates/boot.rb +14 -0
  20. data/generators/config/templates/capybara.rb +156 -0
  21. data/generators/config/templates/custom.yml +2 -3
  22. data/generators/config/templates/default.yml +50 -82
  23. data/generators/cucumber/cucumber_generator.rb +9 -9
  24. data/generators/cucumber/templates/common_steps.rb +4 -4
  25. data/generators/cucumber/templates/cucumber.rake +63 -54
  26. data/generators/cucumber/templates/env.rb +24 -23
  27. data/generators/cucumber/templates/transformers.rb +23 -15
  28. data/generators/emails/emails_generator.rb +4 -2
  29. data/generators/emails/templates/example_email.rb +4 -4
  30. data/generators/prerequisites/prerequisites_generator.rb +24 -0
  31. data/generators/prerequisites/templates/base.rb +22 -0
  32. data/generators/prerequisites/templates/factory_girl.rb +30 -0
  33. data/generators/prerequisites/templates/user.rb +7 -0
  34. data/generators/prerequisites/templates/users.rb +12 -0
  35. data/generators/root/root_generator.rb +11 -7
  36. data/generators/root/templates/.rubocop.yml +32 -0
  37. data/generators/root/templates/Gemfile.erb +27 -0
  38. data/generators/root/templates/Rakefile +6 -8
  39. data/generators/rspec/rspec_generator.rb +7 -7
  40. data/generators/rspec/templates/example_spec.rb +1 -1
  41. data/generators/rspec/templates/rspec.rake +48 -29
  42. data/generators/rspec/templates/spec_helper.rb +33 -32
  43. data/generators/tasks/tasks_generator.rb +4 -2
  44. data/generators/tasks/templates/common.rake +1 -16
  45. data/generators/turnip/templates/.rspec +1 -0
  46. data/generators/turnip/templates/common_steps.rb +25 -0
  47. data/generators/turnip/templates/example.feature +8 -0
  48. data/generators/turnip/templates/spec_helper.rb +56 -0
  49. data/generators/turnip/templates/turnip.rake +61 -0
  50. data/generators/turnip/templates/turnip_helper.rb +6 -0
  51. data/generators/turnip/turnip_generator.rb +26 -0
  52. data/generators/web/templates/example_page.rb +15 -0
  53. data/generators/web/templates/menu_section.rb +13 -0
  54. data/generators/web/web_generator.rb +22 -0
  55. data/howitzer.gemspec +14 -21
  56. data/lib/howitzer.rb +47 -7
  57. data/lib/howitzer/cache.rb +70 -0
  58. data/lib/howitzer/capybara_helpers.rb +194 -0
  59. data/lib/howitzer/email.rb +96 -104
  60. data/lib/howitzer/exceptions.rb +10 -6
  61. data/lib/howitzer/log.rb +120 -0
  62. data/lib/howitzer/mail_adapters.rb +7 -0
  63. data/lib/howitzer/mail_adapters/abstract.rb +84 -0
  64. data/lib/howitzer/mail_adapters/mailgun.rb +115 -0
  65. data/lib/howitzer/mailgun_api.rb +9 -0
  66. data/lib/howitzer/mailgun_api/client.rb +79 -0
  67. data/lib/howitzer/mailgun_api/connector.rb +37 -0
  68. data/lib/howitzer/mailgun_api/response.rb +28 -0
  69. data/lib/howitzer/tasks/framework.rake +2 -2
  70. data/lib/howitzer/utils.rb +7 -1
  71. data/lib/howitzer/utils/string_extensions.rb +66 -0
  72. data/lib/howitzer/version.rb +2 -1
  73. data/lib/howitzer/web.rb +11 -0
  74. data/lib/howitzer/web/base_section.rb +27 -0
  75. data/lib/howitzer/web/blank_page.rb +12 -0
  76. data/lib/howitzer/web/capybara_methods_proxy.rb +29 -0
  77. data/lib/howitzer/web/element_dsl.rb +109 -0
  78. data/lib/howitzer/web/iframe_dsl.rb +93 -0
  79. data/lib/howitzer/web/page.rb +173 -0
  80. data/lib/howitzer/web/page_dsl.rb +64 -0
  81. data/lib/howitzer/web/page_validator.rb +118 -0
  82. data/lib/howitzer/web/section.rb +27 -0
  83. data/lib/howitzer/web/section_dsl.rb +154 -0
  84. data/spec/config/custom.yml +10 -1
  85. data/spec/spec_helper.rb +37 -19
  86. data/spec/support/generator_helper.rb +12 -11
  87. data/spec/support/logger_helper.rb +10 -9
  88. data/spec/support/mailgun_unit_client.rb +52 -44
  89. data/spec/support/shared_examples/capybara_context_holder.rb +33 -0
  90. data/spec/support/shared_examples/capybara_methods_proxy.rb +94 -0
  91. data/spec/support/shared_examples/dynamic_section_methods.rb +35 -0
  92. data/spec/support/shared_examples/element_dsl.rb +119 -0
  93. data/spec/unit/generators/base_generator_spec.rb +64 -33
  94. data/spec/unit/generators/config_generator_spec.rb +11 -7
  95. data/spec/unit/generators/cucumber_generator_spec.rb +26 -17
  96. data/spec/unit/generators/emails_generator_spec.rb +10 -6
  97. data/spec/unit/generators/prerequisites_generator_spec.rb +53 -0
  98. data/spec/unit/generators/root_generator_spec.rb +50 -13
  99. data/spec/unit/generators/rspec_generator_spec.rb +9 -9
  100. data/spec/unit/generators/tasks_generator_spec.rb +6 -6
  101. data/spec/unit/generators/turnip_generator_spec.rb +52 -0
  102. data/spec/unit/generators/web_generator_spec.rb +52 -0
  103. data/spec/unit/lib/cache_spec.rb +85 -0
  104. data/spec/unit/lib/capybara_helpers_spec.rb +696 -0
  105. data/spec/unit/lib/email_spec.rb +104 -91
  106. data/spec/unit/lib/howitzer.rb +31 -0
  107. data/spec/unit/lib/init_spec.rb +0 -1
  108. data/spec/unit/lib/log_spec.rb +122 -0
  109. data/spec/unit/lib/mail_adapters/abstract_spec.rb +62 -0
  110. data/spec/unit/lib/mail_adapters/mailgun_spec.rb +163 -0
  111. data/spec/unit/lib/mailgun_api/client_spec.rb +58 -0
  112. data/spec/unit/lib/mailgun_api/connector_spec.rb +54 -0
  113. data/spec/unit/lib/mailgun_api/response_spec.rb +28 -0
  114. data/spec/unit/lib/utils/string_extensions_spec.rb +77 -0
  115. data/spec/unit/lib/web/base_section_spec.rb +41 -0
  116. data/spec/unit/lib/web/element_dsl_spec.rb +17 -0
  117. data/spec/unit/lib/web/iframe_dsl_spec.rb +99 -0
  118. data/spec/unit/lib/web/page_dsl_spec.rb +52 -0
  119. data/spec/unit/lib/web/page_spec.rb +304 -0
  120. data/spec/unit/lib/web/page_validator_spec.rb +218 -0
  121. data/spec/unit/lib/web/section_dsl_spec.rb +165 -0
  122. data/spec/unit/lib/web/section_spec.rb +61 -0
  123. data/spec/unit/version_spec.rb +1 -1
  124. metadata +116 -203
  125. data/GETTING_STARTED.md +0 -774
  126. data/generators/cucumber/templates/cucumber.yml +0 -10
  127. data/generators/pages/pages_generator.rb +0 -21
  128. data/generators/pages/templates/example_menu.rb +0 -15
  129. data/generators/pages/templates/example_page.rb +0 -15
  130. data/generators/root/templates/Gemfile +0 -7
  131. data/generators/root/templates/boot.rb +0 -10
  132. data/lib/howitzer/blank_page.rb +0 -6
  133. data/lib/howitzer/capybara/dsl_ex.rb +0 -15
  134. data/lib/howitzer/capybara/settings.rb +0 -343
  135. data/lib/howitzer/helpers.rb +0 -230
  136. data/lib/howitzer/init.rb +0 -1
  137. data/lib/howitzer/mailgun/client.rb +0 -65
  138. data/lib/howitzer/mailgun/connector.rb +0 -34
  139. data/lib/howitzer/mailgun/response.rb +0 -28
  140. data/lib/howitzer/patches/rawler_patched.rb +0 -86
  141. data/lib/howitzer/settings.rb +0 -27
  142. data/lib/howitzer/utils/data_generator/data_storage.rb +0 -88
  143. data/lib/howitzer/utils/data_generator/gen.rb +0 -135
  144. data/lib/howitzer/utils/locator_store.rb +0 -217
  145. data/lib/howitzer/utils/log.rb +0 -139
  146. data/lib/howitzer/utils/page_validator.rb +0 -133
  147. data/lib/howitzer/vendor/firebug-1.12.1-fx.xpi +0 -0
  148. data/lib/howitzer/vendor/firepath-0.9.7-fx.xpi +0 -0
  149. data/lib/howitzer/web_page.rb +0 -253
  150. data/spec/active_resource.rb +0 -0
  151. data/spec/config/default.yml +0 -26
  152. data/spec/support/boot_helper.rb +0 -15
  153. data/spec/unit/generators/pages_generator_spec.rb +0 -33
  154. data/spec/unit/lib/capybara/dsl_ex_spec.rb +0 -60
  155. data/spec/unit/lib/capybara/settings_spec.rb +0 -441
  156. data/spec/unit/lib/helpers_spec.rb +0 -1129
  157. data/spec/unit/lib/mailgun/client_spec.rb +0 -36
  158. data/spec/unit/lib/mailgun/connector_spec.rb +0 -70
  159. data/spec/unit/lib/mailgun/response_spec.rb +0 -28
  160. data/spec/unit/lib/settings_spec.rb +0 -17
  161. data/spec/unit/lib/utils/data_generator/data_storage_spec.rb +0 -80
  162. data/spec/unit/lib/utils/data_generator/gen_spec.rb +0 -90
  163. data/spec/unit/lib/utils/locator_store_spec.rb +0 -157
  164. data/spec/unit/lib/utils/log_spec.rb +0 -107
  165. data/spec/unit/lib/utils/page_validator_spec.rb +0 -265
  166. data/spec/unit/lib/web_page_spec.rb +0 -346
@@ -0,0 +1,120 @@
1
+ require 'log4r'
2
+ require 'fileutils'
3
+ require 'active_support/core_ext/module'
4
+
5
+ module Howitzer
6
+ # This class represents logger
7
+ class Log
8
+ include Singleton
9
+ include Log4r
10
+
11
+ class << self
12
+ # Delegates all public instance methods to the class
13
+ delegate :debug, :info, :warn, :fatal, :error, :print_feature_name,
14
+ :settings_as_formatted_text, :print_scenario_name, to: :instance
15
+ end
16
+
17
+ # Outputs debug message if Howitzer.debug_mode == true
18
+ # @param msg [String] a message
19
+
20
+ def debug(msg)
21
+ @logger.debug(msg)
22
+ end
23
+
24
+ # Outputs info message
25
+ # @param msg [String] a message
26
+
27
+ def info(msg)
28
+ @logger.info(msg)
29
+ end
30
+
31
+ # Outputs warn message
32
+ # @param msg [String] a message
33
+
34
+ def warn(msg)
35
+ @logger.warn(msg)
36
+ end
37
+
38
+ # Outputs error message
39
+ # @param msg [String] a message
40
+
41
+ def error(msg)
42
+ @logger.error(msg)
43
+ end
44
+
45
+ # Outputs fatal message
46
+ # @param msg [String] a message
47
+
48
+ def fatal(msg)
49
+ @logger.fatal(msg)
50
+ end
51
+
52
+ # Outputs a feature name into the log with INFO severity
53
+ # @param text [String] a feature name
54
+
55
+ def print_feature_name(text)
56
+ log_without_formatting { info "*** Feature: #{text.upcase} ***" }
57
+ end
58
+
59
+ # Outputs formatted howitzer settings
60
+
61
+ def settings_as_formatted_text
62
+ log_without_formatting { info ::SexySettings::Base.instance.as_formatted_text }
63
+ end
64
+
65
+ # Outputs a scenario name into log with INFO severity
66
+ # @param text [String] a scenario name
67
+
68
+ def print_scenario_name(text)
69
+ log_without_formatting { info " => Scenario: #{text}" }
70
+ end
71
+
72
+ private
73
+
74
+ def initialize
75
+ @logger = Logger.new('ruby_log')
76
+ @logger.add(console_log)
77
+ @logger.add(error_log)
78
+ self.base_formatter = default_formatter
79
+ Logger['ruby_log'].level = Howitzer.debug_mode ? ALL : INFO
80
+ Logger['ruby_log'].trace = true
81
+ end
82
+
83
+ #:nocov:
84
+ def log_without_formatting
85
+ self.base_formatter = blank_formatter
86
+ yield
87
+ self.base_formatter = default_formatter
88
+ end
89
+ #:nocov:
90
+
91
+ def console_log
92
+ StdoutOutputter.new(:console).tap { |o| o.only_at(INFO, DEBUG, WARN) }
93
+ end
94
+
95
+ def error_log
96
+ StderrOutputter.new(:error, 'level' => ERROR)
97
+ end
98
+
99
+ #:nocov:
100
+ def blank_formatter
101
+ PatternFormatter.new(pattern: '%m')
102
+ end
103
+ #:nocov:
104
+
105
+ #:nocov:
106
+ def default_formatter
107
+ params = if Howitzer.hide_datetime_from_log
108
+ { pattern: '[%l] %m' }
109
+ else
110
+ { pattern: '%d [%l] :: %m', date_pattern: '%Y/%m/%d %H:%M:%S' }
111
+ end
112
+ PatternFormatter.new(params)
113
+ end
114
+ #:nocov:
115
+
116
+ def base_formatter=(formatter)
117
+ @logger.outputters.each { |outputter| outputter.formatter = formatter }
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,7 @@
1
+ module Howitzer
2
+ # This module holds all mail adapters
3
+ module MailAdapters
4
+ end
5
+ end
6
+
7
+ require 'howitzer/mail_adapters/abstract'
@@ -0,0 +1,84 @@
1
+ module Howitzer
2
+ module MailAdapters
3
+ # +Abstract+ is the superclass of all mail adapters.
4
+ #
5
+ # @abstract This class should not be used directly. Instead, create a
6
+ # subclass that implements:
7
+ # {.find}
8
+ # {#plain_text_body}
9
+ # {#html_body}
10
+ # {#text}
11
+ # {#mail_from}
12
+ # {#recipients}
13
+ # {#received_time}
14
+ # {#sender_email}
15
+ # {#mime_part}
16
+ class Abstract
17
+ attr_reader :message
18
+
19
+ # Finds an email in mailbox
20
+ # @param recipient [String] an email
21
+ # @param subject [String]
22
+
23
+ def self.find(_recipient, _subject)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # Creates a new instance of email
28
+
29
+ # @param message [Object] original message data
30
+
31
+ def initialize(message)
32
+ @message = message
33
+ end
34
+
35
+ # Returns a plain text body of the email message
36
+
37
+ def plain_text_body
38
+ raise NotImplementedError
39
+ end
40
+
41
+ # Returns a html body of the email message
42
+
43
+ def html_body
44
+ raise NotImplementedError
45
+ end
46
+
47
+ # Returns a mail text
48
+
49
+ def text
50
+ raise NotImplementedError
51
+ end
52
+
53
+ # Returns who has sent email data in format: User Name <user@email>
54
+
55
+ def mail_from
56
+ raise NotImplementedError
57
+ end
58
+
59
+ # Returns an array of recipients who has received current email
60
+
61
+ def recipients
62
+ raise NotImplementedError
63
+ end
64
+
65
+ # Returns email received time
66
+
67
+ def received_time
68
+ raise NotImplementedError
69
+ end
70
+
71
+ # Returns sender user email
72
+
73
+ def sender_email
74
+ raise NotImplementedError
75
+ end
76
+
77
+ # Allows to get email MIME attachment
78
+
79
+ def mime_part
80
+ raise NotImplementedError
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,115 @@
1
+ require 'howitzer/mailgun_api/connector'
2
+ require 'howitzer/exceptions'
3
+ require 'howitzer/mail_adapters/abstract'
4
+
5
+ module Howitzer
6
+ module MailAdapters
7
+ # This class represents Mailgun mail adapter
8
+ class Mailgun < Abstract
9
+ # Finds an email in storage
10
+ # @note emails are stored for 3 days only!
11
+ # @param recipient [String] an email
12
+ # @param subject [String]
13
+ # @raise [EmailNotFoundError] if message blank
14
+
15
+ def self.find(recipient, subject)
16
+ message = {}
17
+ retryable(find_retry_params) { message = retrieve_message(recipient, subject) }
18
+ return new(message) if message.present?
19
+ raise Howitzer::EmailNotFoundError,
20
+ "Message with subject '#{subject}' for recipient '#{recipient}' was not found."
21
+ end
22
+
23
+ # @return [String] plain text body of the email message
24
+
25
+ def plain_text_body
26
+ message['body-plain']
27
+ end
28
+
29
+ # @return [String] html body of the email message
30
+
31
+ def html_body
32
+ message['stripped-html']
33
+ end
34
+
35
+ # @return [String] stripped text
36
+
37
+ def text
38
+ message['stripped-text']
39
+ end
40
+
41
+ # @return [String] an email address specified in `From` field
42
+
43
+ def mail_from
44
+ message['From']
45
+ end
46
+
47
+ # @return [String] recipient emails separated with `, `
48
+
49
+ def recipients
50
+ message['To'].split ', '
51
+ end
52
+
53
+ # @return [String] when email was received
54
+
55
+ def received_time
56
+ message['Received'][/\w+, \d+ \w+ \d+ \d+:\d+:\d+ -\d+ \(\w+\)$/]
57
+ end
58
+
59
+ # @return [String] a real sender email address
60
+
61
+ def sender_email
62
+ message['sender']
63
+ end
64
+
65
+ # @return [Array] attachments
66
+
67
+ def mime_part
68
+ message['attachments']
69
+ end
70
+
71
+ # @raise [NoAttachmentsError] if no attachments present
72
+ # @return [Array] attachments
73
+
74
+ def mime_part!
75
+ files = mime_part
76
+ return files if files.present?
77
+ raise Howitzer::NoAttachmentsError, 'No attachments where found.'
78
+ end
79
+
80
+ def self.events
81
+ MailgunApi::Connector.instance.client.get(
82
+ "#{MailgunApi::Connector.instance.domain}/events", params: { event: 'stored' }
83
+ )
84
+ end
85
+ private_class_method :events
86
+
87
+ def self.event_by(recipient, subject)
88
+ events.to_h['items'].find do |hash|
89
+ hash['message']['recipients'].first == recipient && hash['message']['headers']['subject'] == subject
90
+ end
91
+ end
92
+ private_class_method :event_by
93
+
94
+ def self.find_retry_params
95
+ {
96
+ timeout: Howitzer.mailgun_idle_timeout,
97
+ sleep: Howitzer.mailgun_sleep_time,
98
+ silent: true,
99
+ logger: Howitzer::Log,
100
+ on: Howitzer::EmailNotFoundError
101
+ }
102
+ end
103
+ private_class_method :find_retry_params
104
+
105
+ def self.retrieve_message(recipient, subject)
106
+ event = event_by(recipient, subject)
107
+ raise Howitzer::EmailNotFoundError, 'Message not received yet, retry...' unless event
108
+
109
+ message_url = event['storage']['url']
110
+ MailgunApi::Connector.instance.client.get_url(message_url).to_h
111
+ end
112
+ private_class_method :retrieve_message
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,9 @@
1
+ module Howitzer
2
+ # This module holds simple implementation of mailgun api client
3
+ module MailgunApi
4
+ end
5
+ end
6
+
7
+ require 'howitzer/mailgun_api/response'
8
+ require 'howitzer/mailgun_api/client'
9
+ require 'howitzer/mailgun_api/connector'
@@ -0,0 +1,79 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+ require 'howitzer/mailgun_api/response'
4
+ require 'howitzer/exceptions'
5
+
6
+ module Howitzer
7
+ module MailgunApi
8
+ # A Mailgun::Client object is used to communicate with the Mailgun API. It is a
9
+ # wrapper around RestClient so you don't have to worry about the HTTP aspect
10
+ # of communicating with Mailgun API.
11
+ class Client
12
+ USER_AGENT = 'mailgun-sdk-ruby'.freeze
13
+ attr_reader :api_user, :api_key, :api_host, :api_version, :ssl
14
+ def initialize(api_user: 'api', api_key:, api_host: 'api.mailgun.net', api_version: 'v3', ssl: true)
15
+ @api_user = api_user
16
+ @api_key = api_key
17
+ @api_host = api_host
18
+ @api_version = api_version
19
+ @ssl = ssl
20
+ @http_client = ::RestClient::Resource.new(endpoint, user: api_user, password: api_key, user_agent: USER_AGENT)
21
+ end
22
+
23
+ # Generic Mailgun GET Handler
24
+ #
25
+ # @param resource_path [String] this is the API resource you wish to interact
26
+ # with. Be sure to include your domain, where it is necessary.
27
+ # @param params [Hash] this should be a standard Hash for query
28
+ # containing required parameters for the requested resource.
29
+ # @raise [CommunicationError] if something went wrong
30
+ # @return [Mailgun::Response] a Mailgun::Response object.
31
+
32
+ def get(resource_path, params: nil, accept: '*/*')
33
+ http_params = { accept: accept }
34
+ http_params = http_params.merge(params: params) if params
35
+ response = http_client[resource_path].get(http_params)
36
+ Response.new(response)
37
+ rescue => e
38
+ raise Howitzer::CommunicationError, e.message
39
+ end
40
+
41
+ # Extracts data by url in custom way
42
+ # @note This method was introducted because of saving emails to different nodes.
43
+ # As result we can not use {#get} method, because client holds general api url
44
+ #
45
+ # @param resource_url [String] a full url
46
+ # @param params [Hash] this should be a standard Hash for query
47
+ # containing required parameters for the requested resource.
48
+ # @param accept [String] an accept pattern for headers
49
+ # @raise [CommunicationError] if something went wrong
50
+ # @return [Mailgun::Response] a Mailgun::Response object.
51
+
52
+ def get_url(resource_url, params: nil, accept: '*/*')
53
+ response = ::RestClient::Request.execute(
54
+ method: :get,
55
+ url: resource_url,
56
+ user: api_user,
57
+ password: api_key,
58
+ user_agent: USER_AGENT,
59
+ accept: accept,
60
+ params: params
61
+ )
62
+ Response.new(response)
63
+ rescue => e
64
+ raise Howitzer::CommunicationError, e.message
65
+ end
66
+
67
+ private
68
+
69
+ attr_reader :http_client
70
+
71
+ def endpoint
72
+ scheme = "http#{'s' if ssl}"
73
+ res = "#{scheme}://#{api_host}"
74
+ res << "/#{api_version}" if api_version
75
+ res
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,37 @@
1
+ require 'singleton'
2
+ require 'howitzer/mailgun_api/client'
3
+ require 'howitzer/exceptions'
4
+
5
+ module Howitzer
6
+ module MailgunApi
7
+ # This class represent connector to Mailgun service
8
+ class Connector
9
+ include Singleton
10
+
11
+ attr_reader :api_key
12
+ attr_accessor :domain
13
+
14
+ # Assigns default value for a domain
15
+
16
+ def initialize
17
+ self.domain = Howitzer.mailgun_domain
18
+ end
19
+
20
+ # @return [Client] a mailgun client
21
+ # @raise [InvalidApiKeyError] if api_key is blank
22
+
23
+ def client(api_key = Howitzer.mailgun_key)
24
+ check_api_key(api_key)
25
+ return @client if @api_key == api_key && @api_key
26
+ @api_key = api_key
27
+ @client = Client.new(api_key: @api_key)
28
+ end
29
+
30
+ private
31
+
32
+ def check_api_key(api_key)
33
+ raise Howitzer::InvalidApiKeyError, 'Api key can not be blank' if api_key.blank?
34
+ end
35
+ end
36
+ end
37
+ end