actiontexter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c07c70abba49ae94efaf917157560d5875da1a33
4
+ data.tar.gz: 47ed0798483fcb979995ee767d85b7267f344094
5
+ SHA512:
6
+ metadata.gz: 26b22ffcbd88a798bc69f9d598ab17ef59613c1f5afe4fe69ada7cf80a84fddd02b6a3cf155b7f2e989db1b165cfce920538cf18baa8a6e88b06caae6690f988
7
+ data.tar.gz: 1d05bcc3498f847f4978c025a7d3c766b4bdcf056ae2a74fe256fb3010563452f955471e4cd9f978d8d9985b976ac72628a1aeefd045c1daa6af565084eef0dd
@@ -0,0 +1,7 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ *.swp
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) {{year}} {{fullname}}
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
1
+ = ActionTexter
2
+
3
+ Allows you to build text messages similar to ActionMailer
4
+
5
+ == Installation
6
+
7
+ In your Gemfile add:
8
+
9
+ gem 'action_texter'
10
+
11
+ Install your gems:
12
+
13
+ bundle install
14
+
15
+ That's it!
16
+
17
+ == Configuration
18
+
19
+ In your environments/[RAILS_ENV].rb file, add:
20
+
21
+ config.action_texter.delivery_method = :file
22
+ config.action_texter.file_settings = {}
23
+
24
+ == Contributing
25
+
26
+ If you'd like to contribute to this project, please fork and send me a pull
27
+ request.
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../lib/action_texter/version', __FILE__)
2
+ Gem::Specification.new do |s|
3
+ s.name = "actiontexter"
4
+ s.version = ActionTexter::VERSION::STRING
5
+ s.description = 'Allows you to build text messages similar to ActionMailer'
6
+ s.summary = 'Allows you to build text messages similar to ActionMailer'
7
+ s.add_dependency "activesupport", ">= 3.0.0"
8
+
9
+ s.author = "Jeff Ching"
10
+ s.email = "jeff@chingr.com"
11
+ s.homepage = "http://github.com/chingor13/action_texter"
12
+ s.extra_rdoc_files = ['README.rdoc']
13
+ s.has_rdoc = true
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = Dir.glob('test/*_test.rb')
17
+ end
18
+
@@ -0,0 +1,22 @@
1
+ actionpack_path = File.expand_path('../../../actionpack/lib', __FILE__)
2
+ $:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(actionpack_path)
3
+
4
+ require 'abstract_controller'
5
+ require 'action_view'
6
+ require 'action_texter/version'
7
+
8
+ module ActionTexter
9
+ extend ::ActiveSupport::Autoload
10
+
11
+ autoload :Base
12
+ autoload :Message
13
+ autoload :DeliveryMethods
14
+ autoload :FileDelivery
15
+ autoload :TestDelivery
16
+ autoload :TwilioDelivery
17
+ autoload :WhitelistProxyDelivery
18
+ end
19
+
20
+ if defined?(Rails)
21
+ require 'action_texter/railtie'
22
+ end
@@ -0,0 +1,115 @@
1
+ module ActionTexter
2
+ class Base < AbstractController::Base
3
+ include DeliveryMethods
4
+ abstract!
5
+
6
+ include AbstractController::Logger
7
+ include AbstractController::Rendering
8
+ include AbstractController::Layouts
9
+ include AbstractController::Helpers
10
+ include AbstractController::Translation
11
+ include AbstractController::AssetPaths
12
+
13
+ self.protected_instance_variables = %w(@_action_has_layout)
14
+
15
+ class_attribute :default_params
16
+ self.default_params = {}.freeze
17
+
18
+ class << self
19
+ # Register one or more Observers which will be notified when mail is delivered.
20
+ def register_observers(*observers)
21
+ observers.flatten.compact.each { |observer| register_observer(observer) }
22
+ end
23
+
24
+ # Register one or more Interceptors which will be called before mail is sent.
25
+ def register_interceptors(*interceptors)
26
+ interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
27
+ end
28
+
29
+ # Register an Observer which will be notified when mail is delivered.
30
+ # Either a class or a string can be passed in as the Observer. If a string is passed in
31
+ # it will be <tt>constantize</tt>d.
32
+ def register_observer(observer)
33
+ delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
34
+ Mail.register_observer(delivery_observer)
35
+ end
36
+
37
+ # Register an Interceptor which will be called before mail is sent.
38
+ # Either a class or a string can be passed in as the Interceptor. If a string is passed in
39
+ # it will be <tt>constantize</tt>d.
40
+ def register_interceptor(interceptor)
41
+ delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor)
42
+ Mail.register_interceptor(delivery_interceptor)
43
+ end
44
+
45
+ def texter_name
46
+ @texter_name ||= name.underscore
47
+ end
48
+ attr_writer :texter_name
49
+ alias :controller_path :texter_name
50
+
51
+ def default(value = nil)
52
+ self.default_params = default_params.merge(value).freeze if value
53
+ default_params
54
+ end
55
+
56
+ def respond_to?(method, include_private = false)
57
+ super || action_methods.include?(method.to_s)
58
+ end
59
+
60
+ protected
61
+
62
+ def method_missing(method, *args)
63
+ return super unless respond_to?(method)
64
+ new(method, *args).message
65
+ end
66
+ end
67
+
68
+ attr_internal :message
69
+
70
+ def initialize(method_name = nil, *args)
71
+ super()
72
+ @_message = Message.new
73
+ process(method_name, *args) if method_name
74
+ end
75
+
76
+ def process(*args)
77
+ lookup_context.skip_default_locale!
78
+ super
79
+ end
80
+
81
+ def texter_name
82
+ self.class.texter_name
83
+ end
84
+
85
+ def text(headers={}, &block)
86
+ m = @_message
87
+
88
+ wrap_delivery_behavior!(headers.delete(:delivery_method))
89
+
90
+ # Call all the procs (if any)
91
+ default_values = self.class.default.merge(self.class.default) do |k,v|
92
+ v.respond_to?(:call) ? v.bind(self).call : v
93
+ end
94
+ headers = headers.reverse_merge(default_values)
95
+ headers.each do |k, v|
96
+ m[k] = v
97
+ end
98
+
99
+ templates_path = self.class.texter_name
100
+ templates_name = action_name
101
+
102
+ each_template(templates_path, templates_name) do |template|
103
+ m.body ||= render(:template => template)
104
+ end
105
+ m
106
+ end
107
+
108
+ def each_template(paths, name, &block)
109
+ templates = lookup_context.find_all(name, Array.wrap(paths))
110
+ templates.uniq { |t| t.formats }.each(&block)
111
+ end
112
+
113
+ ActiveSupport.run_load_hooks(:action_texter, self)
114
+ end
115
+ end
@@ -0,0 +1,74 @@
1
+ require 'tmpdir'
2
+
3
+ module ActionTexter
4
+ # This module handles everything related to mail delivery, from registering new
5
+ # delivery methods to configuring the mail object to be sent.
6
+ module DeliveryMethods
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :delivery_methods, :delivery_method
11
+
12
+ # Do not make this inheritable, because we always want it to propagate
13
+ cattr_accessor :raise_delivery_errors
14
+ self.raise_delivery_errors = true
15
+
16
+ cattr_accessor :perform_deliveries
17
+ self.perform_deliveries = true
18
+
19
+ self.delivery_methods = {}.freeze
20
+ self.delivery_method = :file
21
+
22
+ add_delivery_method :file, ActionTexter::FileDelivery,
23
+ :location => defined?(Rails.root) ? "#{Rails.root}/tmp/texts" : "#{Dir.tmpdir}/texts"
24
+ add_delivery_method :test, ActionTexter::TestDelivery
25
+ add_delivery_method :twilio, ActionTexter::TwilioDelivery
26
+ add_delivery_method :whitelist_proxy, ActionTexter::WhitelistProxyDelivery
27
+ end
28
+
29
+ module ClassMethods
30
+ # Provides a list of SMS messages that have been delivered by ActionTexter::TestDelivery
31
+ delegate :deliveries, :deliveries=, :to => ActionTexter::TestDelivery
32
+
33
+ # Adds a new delivery method through the given class using the given symbol
34
+ # as alias and the default options supplied:
35
+ #
36
+ # Example:
37
+ #
38
+ # add_delivery_method :sendmail, Mail::Sendmail,
39
+ # :location => '/usr/sbin/sendmail',
40
+ # :arguments => '-i -t'
41
+ #
42
+ def add_delivery_method(symbol, klass, default_options={})
43
+ class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
44
+ send(:"#{symbol}_settings=", default_options)
45
+ self.delivery_methods = delivery_methods.merge(symbol.to_sym => klass).freeze
46
+ end
47
+
48
+ def wrap_delivery_behavior(message, method=nil) #:nodoc:
49
+ method ||= self.delivery_method
50
+ message.delivery_handler = self
51
+
52
+ case method
53
+ when NilClass
54
+ raise "Delivery method cannot be nil"
55
+ when Symbol
56
+ if klass = delivery_methods[method.to_sym]
57
+ message.delivery_method(klass, send(:"#{method}_settings"))
58
+ else
59
+ raise "Invalid delivery method #{method.inspect}"
60
+ end
61
+ else
62
+ message.delivery_method(method)
63
+ end
64
+
65
+ message.perform_deliveries = perform_deliveries
66
+ message.raise_delivery_errors = raise_delivery_errors
67
+ end
68
+ end
69
+
70
+ def wrap_delivery_behavior!(*args) #:nodoc:
71
+ self.class.wrap_delivery_behavior(@_message, *args)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ module ActionTexter
2
+ class FileDelivery
3
+ attr_reader :location
4
+ def initialize(config = {})
5
+ @location = config[:location]
6
+ raise ArgumentError, "you must specify config.action_texter.file_settings to contain a :location" unless @location
7
+ Dir.mkdir(@location) unless Dir.exists?(@location)
8
+ end
9
+
10
+ def deliver(message)
11
+ File.open(File.join(location, "#{message.to}.txt"), "a") do |file|
12
+ file.puts("FROM: #{message.from}")
13
+ file.puts(message.body)
14
+ file.puts("-"*40)
15
+ end
16
+ true
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ module ActionTexter
2
+ class Message
3
+ attr_accessor :to, :from, :body
4
+
5
+ attr_accessor :delivery_handler, :perform_deliveries, :raise_delivery_errors
6
+ attr_reader :delivery_method, :delivery_options
7
+
8
+ def initialize(attrs = {})
9
+ attrs.each do |k, v|
10
+ self.send("#{k}=", v) if self.respond_to?("#{k}=")
11
+ end
12
+ end
13
+
14
+ def []=(k, v)
15
+ self.send("#{k}=", v) if self.respond_to?("#{k}=")
16
+ end
17
+
18
+ def [](k)
19
+ self.send(k) if self.respond_to?(k)
20
+ end
21
+
22
+ def deliver
23
+ return false unless perform_deliveries
24
+ begin
25
+ @delivery_method.deliver(self)
26
+ rescue => e
27
+ raise e if raise_delivery_errors
28
+ end
29
+ end
30
+
31
+ def delivery_method(method = nil, opts = {})
32
+ unless method
33
+ @delivery_method
34
+ else
35
+ @delivery_method = method.new(opts)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ require "action_texter"
2
+ require "rails"
3
+ require "abstract_controller/railties/routes_helpers"
4
+
5
+ module ActionTexter
6
+ class Railtie < Rails::Railtie
7
+ config.action_texter = ActiveSupport::OrderedOptions.new
8
+
9
+ initializer "action_texter.logger" do
10
+ ActiveSupport.on_load(:action_texter) { self.logger ||= Rails.logger }
11
+ end
12
+
13
+ initializer "action_texter.set_configs" do |app|
14
+ paths = app.config.paths
15
+ options = app.config.action_texter
16
+
17
+ options.assets_dir ||= paths["public"].first
18
+ options.javascripts_dir ||= paths["public/javascripts"].first
19
+ options.stylesheets_dir ||= paths["public/stylesheets"].first
20
+
21
+ # make sure readers methods get compiled
22
+ #options.asset_path ||= app.config.asset_path
23
+ options.asset_host ||= app.config.asset_host
24
+ options.relative_url_root ||= app.config.relative_url_root
25
+
26
+ ActiveSupport.on_load(:action_texter) do
27
+ include AbstractController::UrlFor
28
+ extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
29
+ include app.routes.mounted_helpers
30
+
31
+ register_interceptors(options.delete(:interceptors))
32
+ register_observers(options.delete(:observers))
33
+
34
+ options.each { |k,v| send("#{k}=", v) }
35
+ prepend_view_path(Rails.configuration.paths["app/views"])
36
+ end
37
+ end
38
+
39
+ initializer "action_texter.compile_config_methods" do
40
+ ActiveSupport.on_load(:action_texter) do
41
+ config.compile_methods! if config.respond_to?(:compile_methods!)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ module ActionTexter
2
+ class TestDelivery
3
+ cattr_accessor :deliveries
4
+ self.deliveries = []
5
+
6
+ def initialize(config = {})
7
+ end
8
+
9
+ def deliver(message)
10
+ self.class.deliveries << message
11
+ true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module ActionTexter
2
+ class TwilioDelivery
3
+ attr_reader :client
4
+
5
+ def initialize(config = {})
6
+ @sid = config[:sid]
7
+ @token = config[:token]
8
+ @subaccount = config[:subaccount]
9
+ raise ArgumentError, "you must specify config.action_texter.twilio_settings to contain a :sid" unless @sid
10
+ raise ArgumentError, "you must specify config.action_texter.twilio_settings to contain a :token" unless @token
11
+ @client = Twilio::REST::Client.new(@sid, @token)
12
+ @client = client.accounts.find(@subaccount) if @subaccount
13
+ end
14
+
15
+ def deliver(message)
16
+ client.sms.messages.create(
17
+ :from => message.from,
18
+ :to => message.to,
19
+ :body => message.body.strip
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ module ActionTexter
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+ PRE = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ module ActionTexter
2
+ class WhitelistProxyDelivery
3
+ class BlockedDelivery < StandardError; end
4
+ attr_reader :delivery_method, :whitelist
5
+
6
+ def initialize(config = {})
7
+ @delivery_method = config[:delivery_method]
8
+ @whitelist = config[:whitelist]
9
+ raise ArgumentError, "you must specify config.action_texter.whitelist_proxy_settings to contain a :delivery_method" unless @delivery_method
10
+ raise ArgumentError, "you must specify config.action_texter.whitelist_proxy_settings to contain a :whitelist" unless @whitelist
11
+ end
12
+
13
+ def deliver(message)
14
+ raise BlockedDelivery if blocked?(message.to)
15
+
16
+ real_delivery_method.deliver(message)
17
+ end
18
+
19
+ protected
20
+
21
+ def blocked?(to)
22
+ !whitelist.include?(to.to_s)
23
+ end
24
+
25
+ def real_delivery_method
26
+ @real_delivery_method ||= begin
27
+ settings = ActionTexter::Base.send(:"#{self.delivery_method}_settings")
28
+ ActionTexter::Base.delivery_methods[self.delivery_method].new(settings)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ require 'action_texter'
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actiontexter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeff Ching
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-30 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: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ description: Allows you to build text messages similar to ActionMailer
28
+ email: jeff@chingr.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - .gitignore
35
+ - LICENSE
36
+ - README.rdoc
37
+ - actiontexter.gemspec
38
+ - lib/action_texter.rb
39
+ - lib/action_texter/base.rb
40
+ - lib/action_texter/delivery_methods.rb
41
+ - lib/action_texter/file_delivery.rb
42
+ - lib/action_texter/message.rb
43
+ - lib/action_texter/railtie.rb
44
+ - lib/action_texter/test_delivery.rb
45
+ - lib/action_texter/twilio_delivery.rb
46
+ - lib/action_texter/version.rb
47
+ - lib/action_texter/whitelist_proxy_delivery.rb
48
+ - lib/actiontexter.rb
49
+ homepage: http://github.com/chingor13/action_texter
50
+ licenses: []
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.0.3
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Allows you to build text messages similar to ActionMailer
72
+ test_files: []