paper_plane 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6ab5d44238081d9bd9e9c1dd59577cb978f3dbc1511f854e4a336c299be62c1a
4
+ data.tar.gz: 4e4d5882e678e1ffbbcc35b792b6d8363c5d1711038c2f2494cb125a75f44702
5
+ SHA512:
6
+ metadata.gz: a19ef9859c9dbf035a9f2376fff68d93c5cbc06b0d892eff9330bc317dbda98dea96aa88acc7a2d54ccfda75587118a87340c76a56f7a83f2561138459b2e672
7
+ data.tar.gz: 53d265c286c1b4a74f797f7e8695c08b1a3effbac719cc31b13d4ed69e99b3badec1ba7ab446a7aac5e3a8f4e4fd20b357141507e94e225df64ef8ce5a6f7773
File without changes
@@ -0,0 +1,39 @@
1
+ # PaperPlane
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/paper_plane`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'paper_plane'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install paper_plane
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/paper_plane.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PaperPlaneGenerator < Rails::Generators::NamedBase
4
+ argument :messages, type: :array, default: [], banner: 'action action'
5
+
6
+ TEMPLATE_ROUTES = {
7
+ email: 'md',
8
+ sms: 'text'
9
+ }.freeze
10
+
11
+ def create_paper_plane_file
12
+ template('paper_plane.rb', File.join('app/paper_planes', class_path, "#{file_name}_paper_plane.rb"))
13
+
14
+ messages.each do |message|
15
+ I18n.available_locales.each do |locale|
16
+ flight_routes.each do |route_name, route_extension|
17
+ template(
18
+ "#{route_name}",
19
+ File.join(
20
+ 'app/paper_planes',
21
+ class_path,
22
+ file_name,
23
+ message,
24
+ "#{route_name}.#{locale}.#{route_extension}.erb"
25
+ )
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def flight_routes
33
+ TEMPLATE_ROUTES.except(*options[:skip_routes])
34
+ end
35
+ end
36
+
37
+
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'paper_plane/base'
4
+ require 'paper_plane/flight_route_registerer'
5
+ require 'paper_plane/fly_job'
6
+ require 'paper_plane/callbacks'
7
+
8
+ module PaperPlane
9
+ extend ActiveSupport::Autoload
10
+ end
11
+
12
+ require 'paper_plane/railtie' if defined?(Rails)
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'objectified'
4
+ require 'active_support/callbacks'
5
+ require 'active_support/core_ext/enumerable'
6
+
7
+ require 'paper_plane/callbacks'
8
+ require 'paper_plane/flight_routes/base'
9
+ require 'paper_plane/flight_routes/email'
10
+ require 'paper_plane/flight_routes/sms'
11
+
12
+ # defines PaperPlane::Base, the dad of all paper_planes.
13
+ module PaperPlane
14
+ class Base
15
+ include ActiveSupport::Callbacks
16
+ include Objectified
17
+
18
+ include PaperPlane::Callbacks
19
+
20
+ object_type :paper_plane
21
+
22
+ class << self
23
+ def skip(*flight_routes_types)
24
+ define_method(:skipped_flight_routes) do
25
+ @skipped_flight_routes = flight_routes_types
26
+ end
27
+ end
28
+
29
+ def flight_routes
30
+ @flight_routes ||= {}
31
+ end
32
+
33
+ def register_flight_route(route_name, flight_route)
34
+ flight_routes[route_name] = flight_route
35
+ end
36
+
37
+ def template_formats(**map)
38
+ @template_formats = map || {}
39
+ end
40
+
41
+ def fly_action(mid, **kwargs)
42
+ new(**kwargs).tap do |paper_plane|
43
+ paper_plane.run_callbacks(:flying) do
44
+ paper_plane.send(mid)
45
+ paper_plane.fly(mid)
46
+ end
47
+ end
48
+ end
49
+
50
+ def method_missing(mid, *args, &block)
51
+ if instance_methods(false).include? mid
52
+ fly_action(mid, *args)
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ def respond_to_missing?(method_name, include_private = false)
59
+ instance_methods(false).include?(method_name) || super
60
+ end
61
+ end
62
+
63
+ def self.inherited(subclass)
64
+ subclass.class_eval do
65
+ object_type :paper_plane
66
+ register_flight_route :email, PaperPlane::FlightRoutes::Email
67
+ register_flight_route :sms, PaperPlane::FlightRoutes::Sms
68
+ end
69
+ end
70
+
71
+ attr_reader :flight_routes, :params, :mid
72
+
73
+ # set the routes to fly
74
+ def initialize(**kwargs)
75
+ @template_formats = template_formats
76
+ @skipped_flight_routes = []
77
+ @flight_routes = self.class.flight_routes
78
+ @paper_plane_name = base_klass_string
79
+ @recipient ||= kwargs.delete(:to)
80
+ @async ||= kwargs.delete(:async) || ENV['RAILS_ENV'] == 'development'
81
+ @params = kwargs
82
+ end
83
+
84
+ # set message and call private do_fly method
85
+ def fly(mid)
86
+ @mid = mid
87
+
88
+ if @async
89
+ do_fly
90
+ else
91
+ PaperPlane::FlyJob.fly_later(self.class.to_s, mid, **params)
92
+ end
93
+ end
94
+
95
+ # flies without enqueing jobs
96
+ def fly_now!(mid)
97
+ @async = true
98
+
99
+ fly(mid)
100
+ end
101
+
102
+ # determines which routes the paper_plane should skip
103
+ def skip(*flight_routes_types)
104
+ @skipped_flight_routes.concat(flight_routes_types)
105
+ end
106
+
107
+ # determines whether the piegon is going to fly this route
108
+ def flying_route?(route_type)
109
+ skipped_flight_routes.exclude? route_type
110
+ end
111
+
112
+ # extracts context from the method in the paper_plane, to be injected in each flight route
113
+ def context
114
+ instance_variables.map { |attribute| [attribute, instance_variable_get(attribute)] }.to_h
115
+ end
116
+
117
+ private
118
+
119
+ attr_reader :skipped_flight_routes
120
+
121
+ def do_fly
122
+ flight_routes.each do |route_name, _route_object|
123
+ # next unless route.fly?(args)
124
+ next unless flying_route?(route_name)
125
+
126
+ fly_route(route_name)
127
+ end
128
+ self
129
+ end
130
+
131
+ def fly_route(type)
132
+ raise NoMessageError, 'There are no messages to deliver' unless mid
133
+
134
+ begin
135
+ flight_routes[type].fly(mid, context, **params)
136
+ rescue
137
+ _logger.error "Error in #{self.class}##{mid}: Could not send #{type.to_s.titleize}!."
138
+ else
139
+ _logger.debug "#{type.to_s.titleize} processed."
140
+ end
141
+ end
142
+
143
+ def template_formats
144
+ self.class.template_formats
145
+ end
146
+
147
+ def _logger
148
+ @_logger ||= Logger.new(STDOUT)
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/version'
4
+ require 'active_support/callbacks'
5
+ require 'active_support/concern'
6
+
7
+ module PaperPlane
8
+ # Add callbacks support to Active Delivery (requires ActiveSupport::Callbacks)
9
+ #
10
+ # # Run method before delivering notification
11
+ # # NOTE: when `false` is returned the executation is halted
12
+ # before_fly :do_something
13
+ #
14
+ # # You can specify a notification method (to run callback only for that method)
15
+ # before_fly :do_mail_something, on: :mail
16
+ #
17
+ # # or for push notifications
18
+ # before_fly :do_mail_something, on: :push
19
+ #
20
+ # # after_ and around_ callbacks are also supported
21
+ # after_fly :cleanup
22
+ #
23
+ # around_fly :set_context
24
+ CALLBACK_TERMINATOR = if ::ActiveSupport::VERSION::MAJOR >= 5
25
+ ->(_target, result) { result.call == false }
26
+ else
27
+ ->(_target, result) { result == false }
28
+ end
29
+
30
+ module Callbacks
31
+ extend ActiveSupport::Concern
32
+
33
+ included do
34
+ include ActiveSupport::Callbacks
35
+
36
+ define_flight_callbacks :flying
37
+ end
38
+
39
+ class_methods do
40
+ def _normalize_callback_options(options)
41
+ _normalize_callback_option(options, :only, :if)
42
+ _normalize_callback_option(options, :except, :unless)
43
+ end
44
+
45
+ def _normalize_callback_option(options, from, to)
46
+ if (from = options[from])
47
+ from_set = Array(from).map(&:to_s).to_set
48
+ from = proc { |c| from_set.include? c.notification_name.to_s }
49
+ options[to] = Array(options[to]).unshift(from)
50
+ end
51
+ end
52
+
53
+ def define_flight_callbacks(route_name)
54
+ define_callbacks route_name,
55
+ terminator: CALLBACK_TERMINATOR,
56
+ skip_after_callbacks_if_terminated: true
57
+ end
58
+
59
+ def before_flying(method_or_block = nil, on: :flying, **options, &block)
60
+ method_or_block ||= block
61
+ _normalize_callback_options(options)
62
+ set_callback on, :before, method_or_block, options
63
+ end
64
+
65
+ def after_flying(method_or_block = nil, on: :flying, **options, &block)
66
+ method_or_block ||= block
67
+ _normalize_callback_options(options)
68
+ set_callback on, :after, method_or_block, options
69
+ end
70
+
71
+ def around_flying(method_or_block = nil, on: :flying, **options, &block)
72
+ method_or_block ||= block
73
+ _normalize_callback_options(options)
74
+ set_callback on, :around, method_or_block, options
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'paper_plane/flight_routes/base'
4
+ require 'paper_plane/flight_routes/email'
5
+ require 'paper_plane/flight_routes/sms'
6
+
7
+ module PaperPlane
8
+ module FlightRouteRegisterer
9
+ def self.call(klass)
10
+ klass.class_eval do
11
+ extend ClassMethods
12
+
13
+ register_email
14
+ register_channel
15
+ register_sms
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ def register_email
21
+ end
22
+
23
+ def register_channel
24
+ end
25
+
26
+ def register_sms
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ # object_klass = begin
33
+ # object_klass_for(:deliverer)
34
+ # rescue NameError
35
+ # nil
36
+ # end
@@ -0,0 +1,200 @@
1
+ require 'paper_plane/flight_routes/class_methods'
2
+
3
+ module PaperPlane
4
+ module FlightRoutes
5
+ NoRecipientError = Class.new(ArgumentError)
6
+ NoTemplateError = Class.new(ArgumentError)
7
+ DoFlyUndefined = Class.new(NoMethodError)
8
+
9
+ class Base
10
+ def self.inherited(subklass)
11
+ subklass.class_eval do
12
+ extend PaperPlane::FlightRoutes::ClassMethods
13
+ default_views 'app/paper_planes'
14
+ end
15
+ end
16
+
17
+ attr_accessor :context, :recipient
18
+
19
+ def initialize(route_name = nil)
20
+ @_route_name = route_name || _default_route_name
21
+ @_engine = _default_engine
22
+ end
23
+
24
+ def self.fly(mid, context, **args)
25
+ new.fly(mid, context, **args)
26
+ end
27
+
28
+ # to be overriden by children
29
+ def fly(mid, context, **args)
30
+ @method = mid
31
+ @args = args
32
+ @context = context
33
+
34
+ _extract_recipient
35
+ _extract_template_formats
36
+ _extract_paper_plane_name
37
+
38
+ begin
39
+ do_fly
40
+ rescue NoTemplateError
41
+ _logger.debug "'#{route_name}' skipped for lack of suited template => path: '#{_template_file_path}'; extension: #{_template_formats}."
42
+ else
43
+ _logger.debug "#{route_name} sent!"
44
+ end
45
+ end
46
+
47
+ def do_fly
48
+ raise DoFlyUndefined, 'Please override :do_fly in your flight route.'
49
+ end
50
+
51
+ private
52
+
53
+ def contextualize
54
+ context.each do |variable, value|
55
+ next unless variable.to_s.starts_with? '@'
56
+
57
+ instance_variable_set(variable, value)
58
+ end
59
+ end
60
+
61
+ def action
62
+ @method.to_s
63
+ end
64
+
65
+ def route_name
66
+ @_route_name.to_s
67
+ end
68
+
69
+ def template
70
+ return _renderer.render(*_render_payload) if _template_exists?
71
+
72
+ raise NoTemplateError, "Could not find template for '#{_template_file_path}' with extension: #{_template_formats}"
73
+ end
74
+
75
+ def locale
76
+ @locale || @recipient.locale || I18n.locale
77
+ end
78
+
79
+ def _render_payload
80
+ [
81
+ _view_context,
82
+ template: _template_file_path,
83
+ locals: _template_locals
84
+ ]
85
+ end
86
+
87
+ def _logger
88
+ @_logger ||= Logger.new(STDOUT)
89
+ end
90
+
91
+ def _template_locals
92
+ context
93
+ end
94
+
95
+ def _lookup_context
96
+ @_lookup_context ||= ActionView::LookupContext.new(_view_resolver)
97
+ end
98
+
99
+ def _view_resolver
100
+ @_view_resolver ||= ActionView::FileSystemResolver.new(_default_views_folder)
101
+ end
102
+
103
+ def _view_context
104
+ @_view_context ||= ActionView::Base.new(_lookup_context)
105
+ end
106
+
107
+ # def _output_buffer
108
+ # @_output_buffer ||= ActionView::OutputBuffer.new
109
+ # end
110
+
111
+ def _renderer
112
+ @_renderer ||= ActionView::Renderer.new(_lookup_context)
113
+ end
114
+
115
+ def _template_formats
116
+ @_template_formats = %i[text]
117
+ end
118
+
119
+ def _extract_template_formats
120
+ @_template_formats = @context.dig(:@template_formats)
121
+ end
122
+
123
+ def _extract_paper_plane_name
124
+ @_paper_plane_name = @context.dig(:@paper_plane_name)
125
+ end
126
+
127
+ def _extract_recipient
128
+ unless @context.key?(:@recipient)
129
+ raise NoRecipientError, 'please specify the recipient value by setting @to = recipient'
130
+ end
131
+
132
+ @recipient = @context.dig(:@recipient)
133
+ end
134
+
135
+ def _template_file_path
136
+ [_template_folder, _template_name].join('/')
137
+ end
138
+
139
+ def _template_name
140
+ if _localized_template_exists?
141
+ _localized_template_name
142
+ else
143
+ _base_template_name
144
+ end
145
+ end
146
+
147
+ def _localized_file_path
148
+ File.join(_full_template_folder_path, _localized_template_name)
149
+ end
150
+
151
+ def _localized_template_name
152
+ [_base_template_name, '.', locale].join
153
+ end
154
+
155
+ def _base_template_name
156
+ [action, route_name].join('/')
157
+ end
158
+
159
+ def _full_template_folder_path
160
+ Rails.root.join(_default_views_folder, _template_folder)
161
+ end
162
+
163
+ def _template_folder
164
+ _paper_plane_templates_path
165
+ end
166
+
167
+ def _template_full_file_path
168
+ File.join(_full_template_folder_path, _template_name)
169
+ end
170
+
171
+ def _default_engine
172
+ self.class._default_engine
173
+ end
174
+
175
+ def _default_template_format
176
+ self.class._default_template_format
177
+ end
178
+
179
+ def _default_views_folder
180
+ Rails.root.join(self.class._default_views_folder)
181
+ end
182
+
183
+ def _paper_plane_templates_path
184
+ @_paper_plane_name.underscore
185
+ end
186
+
187
+ def _default_route_name
188
+ self.class.to_s.underscore.split('/').last
189
+ end
190
+
191
+ def _template_exists?
192
+ !Dir.glob([_template_full_file_path, '*.*'].join).empty?
193
+ end
194
+
195
+ def _localized_template_exists?
196
+ !Dir.glob([_localized_file_path, '*.*'].join).empty?
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,31 @@
1
+ module PaperPlane
2
+ module FlightRoutes
3
+ module ClassMethods
4
+ def default_engine(engine)
5
+ @engine = engine
6
+ end
7
+
8
+ def default_views(folder_path)
9
+ @default_views_folder = folder_path
10
+ end
11
+
12
+ def default_format(format)
13
+ @default_template_format = format
14
+ end
15
+
16
+ private
17
+
18
+ def _default_views_folder
19
+ @default_views_folder
20
+ end
21
+
22
+ def _engine
23
+ @engine
24
+ end
25
+
26
+ def _default_template_format
27
+ @default_template_format
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ require 'action_mailer'
2
+
3
+ module PaperPlane
4
+ module FlightRoutes
5
+ class Email < Base
6
+ default_engine ActionMailer::Base
7
+
8
+ private
9
+
10
+ def do_fly
11
+ _preprend_view_lookup
12
+ _insert_mailer_method
13
+ _set_layout
14
+
15
+ @_template_formats = %i[html text]
16
+
17
+ mail = @_engine.send(@method, context.merge(headers: headers))
18
+
19
+ if Rails.env.development?
20
+ LetterOpener::DeliveryMethod.new.deliver!(mail)
21
+ else
22
+ mail.deliver!
23
+ end
24
+ end
25
+
26
+ def headers
27
+ {
28
+ template_path: _template_folder,
29
+ template_name: _template_name,
30
+ subject: subject,
31
+ to: recipient.email,
32
+ from: 'Christophe Vercarre <christophe@colochousing.com>',
33
+ charset: 'utf-8',
34
+ bcc: ENV['EMAIL_INTERCEPTOR_RECIPIENTS'].split(',')
35
+ }
36
+ end
37
+
38
+ def subject
39
+ @context.dig(:@subject)
40
+ end
41
+
42
+ def _insert_mailer_method
43
+ @_engine.define_method(@method) do |context|
44
+ context.each do |var, _v|
45
+ next unless var.to_s.starts_with? '@'
46
+
47
+ instance_variable_set(var, context.dig(var))
48
+ end
49
+ mail(context[:headers])
50
+ end
51
+ end
52
+
53
+ def _preprend_view_lookup
54
+ @_engine.prepend_view_path _default_views_folder
55
+ end
56
+
57
+ def _set_layout
58
+ @_engine.layout 'email'
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ require 'twilio-ruby'
2
+
3
+ module PaperPlane
4
+ module FlightRoutes
5
+ class Sms < Base
6
+ default_engine Twilio::REST::Client.new(ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN'])
7
+
8
+ def do_fly
9
+ return if intercept?
10
+
11
+ @_engine.create(message_payload)
12
+ end
13
+
14
+ def message_payload
15
+ {
16
+ from: ENV['TWILIO_NUMBER'],
17
+ to: recipient.full_mobile_number,
18
+ body: template
19
+ }
20
+ end
21
+
22
+ def intercept?; end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_job'
2
+
3
+ module PaperPlane
4
+ class FlyJob < ActiveJob::Base
5
+ queue_as :paper_planes
6
+
7
+ class << self
8
+ alias_method :fly_later, :perform_later
9
+ end
10
+
11
+ def perform(paper_plane_name, action_name, **args)
12
+ paper_plane_name.constantize.fly_action(action_name, **args.merge(async: true))
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'railties/rails/railtie'
4
+
5
+ module PaperPlane
6
+ class Railtie < ::Rails::Railtie
7
+ config.eager_load_namespaces << PaperPlane
8
+
9
+ # generators do
10
+ # require 'path/to/my_railtie_generator'
11
+ # end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module PaperPlane
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1 @@
1
+ <%% message.subject = "New Email" %>
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>PaperPlane < PaperPlane::Base
3
+ <% messages.each do |message| -%>
4
+ def <%= message %>
5
+ end
6
+ <%= "\n" unless message == messages.last -%>
7
+ <% end -%>
8
+ end
9
+ <% end -%>
File without changes
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paper_plane
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Guilherme Andrade
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 6.0.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '6.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 6.0.3
33
+ - !ruby/object:Gem::Dependency
34
+ name: actionmailer
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '6.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 6.0.3
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '6.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 6.0.3
53
+ - !ruby/object:Gem::Dependency
54
+ name: activejob
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '6.0'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 6.0.3
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '6.0'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 6.0.3
73
+ - !ruby/object:Gem::Dependency
74
+ name: twilio-ruby
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '5.27'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 5.27.1
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.27'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 5.27.1
93
+ - !ruby/object:Gem::Dependency
94
+ name: objectified
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 0.1.3
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 0.1.3
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 0.1.3
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: 0.1.3
113
+ - !ruby/object:Gem::Dependency
114
+ name: railties
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '6.0'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 6.0.3
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '6.0'
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 6.0.3
133
+ description: A featherweight library for multi thread message deliveries.
134
+ email:
135
+ - guilherme.andrade.ao@gmail.com
136
+ executables: []
137
+ extensions: []
138
+ extra_rdoc_files: []
139
+ files:
140
+ - Changelog.md
141
+ - README.md
142
+ - lib/generators/paper_plane_generator.rb
143
+ - lib/paper_plane.rb
144
+ - lib/paper_plane/base.rb
145
+ - lib/paper_plane/callbacks.rb
146
+ - lib/paper_plane/flight_route_registerer.rb
147
+ - lib/paper_plane/flight_routes/base.rb
148
+ - lib/paper_plane/flight_routes/class_methods.rb
149
+ - lib/paper_plane/flight_routes/email.rb
150
+ - lib/paper_plane/flight_routes/sms.rb
151
+ - lib/paper_plane/fly_job.rb
152
+ - lib/paper_plane/railtie.rb
153
+ - lib/paper_plane/version.rb
154
+ - lib/templates/paper_plane/email.tt
155
+ - lib/templates/paper_plane/paper_plane.rb.tt
156
+ - lib/templates/paper_plane/sms.tt
157
+ homepage: https://github.com/guilherme-andrade/paper_plane
158
+ licenses:
159
+ - MIT
160
+ metadata:
161
+ homepage_uri: https://github.com/guilherme-andrade/paper_plane
162
+ source_code_uri: https://github.com/guilherme-andrade/paper_plane
163
+ changelog_uri: https://github.com/guilherme-andrade/paper_plane/blob/master/Changelog.md
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubygems_version: 3.0.3
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: A featherweight library for multi thread message deliveries.
183
+ test_files: []