textris 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.
- checksums.yaml +7 -0
- data/README.md +118 -0
- data/lib/textris.rb +8 -0
- data/lib/textris/base.rb +75 -0
- data/lib/textris/delivery.rb +16 -0
- data/lib/textris/delivery/mail.rb +95 -0
- data/lib/textris/delivery/test.rb +29 -0
- data/lib/textris/message.rb +65 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2fd3e9eb6888e74d470bde1afe44a785ecbec855
|
4
|
+
data.tar.gz: b32e98392db542754742c288849125af7f7b28fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 352443cb1e2001e43ae58a11d863f80ec5b11b84956aae8f5cd654f75a0da56f313d79b683b27194a5768d8485733a5f11a016366cbf404450bb1ba6bf5b620b
|
7
|
+
data.tar.gz: 4b90542d764e5b78a0cd682065f5df71050cb05f0a971d21979a43627c2e631b8f55b7420efa97fe2ef07fe2416799e4112688a337755355bdfc0e7533322a4a
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# Textris
|
2
|
+
|
3
|
+
Simple gem for implementing texter classes which allow sending SMS messages in similar way to how e-mails are implemented and sent with ActionMailer-based mailers.
|
4
|
+
|
5
|
+
Unlike similar gems, **Textris** has some unique features:
|
6
|
+
|
7
|
+
- phone number E164 validation and normalization with the [Phony](https://github.com/floere/phony) gem
|
8
|
+
- multiple, per-environment configurable delivery methods
|
9
|
+
- e-mail proxy allowing to inspect messages using [Mailinator](https://mailinator.com/) or similar service
|
10
|
+
- support for testing using self-explanatory `Textris::Base.deliveries`
|
11
|
+
- simple, extensible code written from the ground up instead of copying *ActionMailer*
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add to `Gemfile`:
|
16
|
+
|
17
|
+
gem 'textris'
|
18
|
+
|
19
|
+
And run:
|
20
|
+
|
21
|
+
bundle install
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Place texter classes in `app/texters` (e.g. `app/texters/user_texter.rb`):
|
26
|
+
|
27
|
+
class UserTexter < Textris::Base
|
28
|
+
default :from => "Our Team <+48 666-777-888>"
|
29
|
+
|
30
|
+
def welcome(user)
|
31
|
+
@user = user
|
32
|
+
|
33
|
+
text :to => @user.phone
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Place relevant view templates in `app/views/<texter_name>/<action_name>.text.*`, (e.g. `app/views/user_texter/welcome.text.erb`):
|
38
|
+
|
39
|
+
Welcome to our system, <%= @user.name %>!
|
40
|
+
|
41
|
+
Invoke them from application logic:
|
42
|
+
|
43
|
+
class User < ActiveRecord::Base
|
44
|
+
after_create do
|
45
|
+
UserTexter.welcome(self).deliver
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
## Testing
|
50
|
+
|
51
|
+
Access all messages that were sent with the `:test` delivery:
|
52
|
+
|
53
|
+
Textris::Base.deliveries
|
54
|
+
|
55
|
+
You may want to clear the delivery queue before each test:
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
Textris::Base.deliveries.clear
|
59
|
+
end
|
60
|
+
|
61
|
+
Keep in mind that messages targeting multiple phone numbers, like:
|
62
|
+
|
63
|
+
text :to => ['48111222333', '48222333444']
|
64
|
+
|
65
|
+
will yield multiple message deliveries, each for specific phone number.
|
66
|
+
|
67
|
+
## Configuration
|
68
|
+
|
69
|
+
You can change default settings by placing them in any of environment files, like `development.rb` or `test.rb`, or setting them globally in `application.rb`.
|
70
|
+
|
71
|
+
Choose the delivery method:
|
72
|
+
|
73
|
+
# Don't send anything, access your messages via Textris::Base.deliveries
|
74
|
+
config.textris_delivery_method = :test
|
75
|
+
|
76
|
+
# Send e-mails instead of SMSes in order to inspect their content
|
77
|
+
config.textris_delivery_method = :mail
|
78
|
+
|
79
|
+
Configure the mail delivery:
|
80
|
+
|
81
|
+
# E-mail sender, here: "our-team-48666777888@test.app-name.com"
|
82
|
+
config.textris_mail_from_template = '%{from_name:d}-%{from_phone}@%{env:d}.%{app:d}.com'
|
83
|
+
|
84
|
+
# E-mail target, here: "app-name-test-48111222333-texts@mailinator.com"
|
85
|
+
config.textris_mail_to_template = '%{app:d}-%{env:d}-%{to_phone}-texts@mailinator.com'
|
86
|
+
|
87
|
+
# E-mail subject, here: "User texter: Welcome"
|
88
|
+
config.textris_mail_subject_template = '%{texter:dh} texter: %{action:h}'
|
89
|
+
|
90
|
+
# E-mail body, here: "Welcome to our system, Mr Jones!"
|
91
|
+
config.textris_mail_body_template = '%{content}'
|
92
|
+
|
93
|
+
### Template interpolation
|
94
|
+
|
95
|
+
You can use the following interpolations in your mail templates:
|
96
|
+
|
97
|
+
- `app`: application name (like `AppName`)
|
98
|
+
- `env`: enviroment name (like `test` or `production`)
|
99
|
+
- `texter`: texter name (like `User`)
|
100
|
+
- `action`: action name (like `welcome`)
|
101
|
+
- `from_name`: name of the sender (like `Our Team`)
|
102
|
+
- `from_phone`: phone number of the sender (like `48666777888`)
|
103
|
+
- `to_phone`: phone number of the recipient (like `48111222333`)
|
104
|
+
- `content`: message content (like `Welcome to our system, Mr Jones!`)
|
105
|
+
|
106
|
+
You can add optional interpolation modifiers using the `%{variable:modifiers}` syntax. These are most useful for making names e-mail friendly. The following modifiers are available:
|
107
|
+
|
108
|
+
- `d`: dasherize (for instance, `AppName` becomes `app-name`)
|
109
|
+
- `h`: humanize (for instance, `user_name` becomes `User name`)
|
110
|
+
- `p`: format phone (for instance, `48111222333` becomes `+48 111 222 333`)
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
1. Fork it (https://github.com/visualitypl/codegrade/fork)
|
115
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
116
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create a new Pull Request
|
data/lib/textris.rb
ADDED
data/lib/textris/base.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'render_anywhere'
|
2
|
+
|
3
|
+
module Textris
|
4
|
+
class Base
|
5
|
+
include RenderAnywhere
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def deliveries
|
9
|
+
::Textris::Delivery::Test.messages
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_defaults(options)
|
13
|
+
(@defaults || {}).merge(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def default(options)
|
19
|
+
@defaults ||= {}
|
20
|
+
@defaults.merge!(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def method_missing(method_name, *args)
|
26
|
+
self.new(method_name, *args).call_action
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class RenderingController < RenderAnywhere::RenderingController
|
31
|
+
def default_url_options
|
32
|
+
ActionMailer::Base.default_url_options || {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(action, *args)
|
37
|
+
@action = action
|
38
|
+
@args = args
|
39
|
+
end
|
40
|
+
|
41
|
+
def call_action
|
42
|
+
send(@action, *@args)
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def text(options = {})
|
48
|
+
set_instance_variables_for_rendering
|
49
|
+
|
50
|
+
options = self.class.with_defaults(options)
|
51
|
+
options.merge!(
|
52
|
+
:texter => self.class,
|
53
|
+
:action => @action,
|
54
|
+
:content => options[:body].is_a?(String) ? options[:body] : render(
|
55
|
+
:template => template_name, :formats => ['text']))
|
56
|
+
|
57
|
+
::Textris::Message.new(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def template_name
|
63
|
+
class_name = self.class.to_s.underscore.sub('texter/', '')
|
64
|
+
action_name = @action
|
65
|
+
|
66
|
+
"#{class_name}/#{action_name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_instance_variables_for_rendering
|
70
|
+
instance_variables.each do |var|
|
71
|
+
set_instance_variable(var.to_s.sub('@', ''), instance_variable_get(var))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Textris
|
2
|
+
module Delivery
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def get
|
6
|
+
case Rails.application.config.try(:textris_delivery_method).to_s
|
7
|
+
when 'mail'
|
8
|
+
::Textris::Delivery::Mail
|
9
|
+
when 'test'
|
10
|
+
::Textris::Delivery::Test
|
11
|
+
else
|
12
|
+
::Textris::Delivery::Test
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Textris
|
2
|
+
module Delivery
|
3
|
+
class Mail
|
4
|
+
class Mailer < ActionMailer::Base
|
5
|
+
def notify(from, to, subject, body)
|
6
|
+
mail :from => from, :to => to, :subject => subject, :body => body
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def send_message_to_all(message)
|
12
|
+
message.to.each do |to|
|
13
|
+
send_message(to, message)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def send_message(to, message)
|
20
|
+
template_vars = { :to_phone => to }
|
21
|
+
|
22
|
+
from = apply_template from_template, message, template_vars
|
23
|
+
to = apply_template to_template, message, template_vars
|
24
|
+
subject = apply_template subject_template, message, template_vars
|
25
|
+
body = apply_template body_template, message, template_vars
|
26
|
+
|
27
|
+
::Textris::Delivery::Mail::Mailer.notify(
|
28
|
+
from, to, subject, body).deliver
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_template
|
32
|
+
Rails.application.config.try(:textris_mail_from_template) ||
|
33
|
+
"%{from_name:d}-%{from_phone}@%{env:d}.%{app:d}.com"
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_template
|
37
|
+
Rails.application.config.try(:textris_mail_to_template) ||
|
38
|
+
"%{app:d}-%{env:d}-%{to_phone}-texts@mailinator.com"
|
39
|
+
end
|
40
|
+
|
41
|
+
def subject_template
|
42
|
+
Rails.application.config.try(:textris_mail_subject_template) ||
|
43
|
+
"%{texter:dh} texter: %{action:h}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def body_template
|
47
|
+
Rails.application.config.try(:textris_mail_body_template) ||
|
48
|
+
"%{content}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def apply_template(template, message, vars)
|
52
|
+
template.gsub(/\%\{[a-z_:]+\}/) do |match|
|
53
|
+
directive = match.gsub(/[%{}]/, '')
|
54
|
+
var = directive.split(':').first
|
55
|
+
modifiers = directive.split(':')[1] || ''
|
56
|
+
|
57
|
+
content = if var == 'app'
|
58
|
+
Rails.application.class.parent_name
|
59
|
+
elsif var == 'env'
|
60
|
+
Rails.env
|
61
|
+
elsif var == 'texter' && (texter = message.texter).present?
|
62
|
+
texter.to_s.split('::').last.sub(/Texter$/, '')
|
63
|
+
elsif var == 'action' && (action = message.action).present?
|
64
|
+
action.to_s
|
65
|
+
elsif var == 'from_name' && (from = message.from_name).present?
|
66
|
+
from.to_s
|
67
|
+
elsif (value = vars[var.to_sym]).present?
|
68
|
+
value
|
69
|
+
elsif ['content', 'from_phone'].include?(var)
|
70
|
+
message.send(var)
|
71
|
+
end.to_s.strip
|
72
|
+
|
73
|
+
unless content.present?
|
74
|
+
content = 'unknown'
|
75
|
+
end
|
76
|
+
|
77
|
+
if modifiers.include?('d')
|
78
|
+
content = content.underscore.dasherize
|
79
|
+
end
|
80
|
+
|
81
|
+
if modifiers.include?('h')
|
82
|
+
content = content.humanize.gsub(/[-_]/, ' ')
|
83
|
+
end
|
84
|
+
|
85
|
+
if modifiers.include?('p')
|
86
|
+
content = Phony.format(content) rescue content
|
87
|
+
end
|
88
|
+
|
89
|
+
content
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Textris
|
2
|
+
module Delivery
|
3
|
+
class Test
|
4
|
+
class << self
|
5
|
+
def send_message_to_all(message)
|
6
|
+
message.to.each do |to|
|
7
|
+
send_message(to, message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def messages
|
12
|
+
@messages ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def send_message(to, message)
|
18
|
+
messages.push(::Textris::Message.new(
|
19
|
+
:content => message.content,
|
20
|
+
:from_name => message.from_name,
|
21
|
+
:from_phone => message.from_phone,
|
22
|
+
:texter => message.texter,
|
23
|
+
:action => message.action,
|
24
|
+
:to => to))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Textris
|
2
|
+
class Message
|
3
|
+
attr_reader :content, :from_name, :from_phone, :to, :texter, :action
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@to = parse_to options[:to]
|
7
|
+
@content = parse_content options[:content]
|
8
|
+
|
9
|
+
if options.has_key?(:from)
|
10
|
+
@from_name, @from_phone = parse_from options[:from]
|
11
|
+
else
|
12
|
+
@from_name = options[:from_name]
|
13
|
+
@from_phone = options[:from_phone]
|
14
|
+
end
|
15
|
+
|
16
|
+
unless @content.present?
|
17
|
+
raise(ArgumentError, "Content must be provided")
|
18
|
+
end
|
19
|
+
|
20
|
+
unless @to.present?
|
21
|
+
raise(ArgumentError, "Recipients must be provided and E.164 compilant")
|
22
|
+
end
|
23
|
+
|
24
|
+
@texter = options[:texter]
|
25
|
+
@action = options[:action]
|
26
|
+
end
|
27
|
+
|
28
|
+
def deliver
|
29
|
+
delivery = ::Textris::Delivery.get
|
30
|
+
delivery.send_message_to_all(self)
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def parse_from(from)
|
38
|
+
if from.blank?
|
39
|
+
nil
|
40
|
+
elsif (matches = from.match(/(.*)\<(.*)\>\s*$/).to_a).size == 3 &&
|
41
|
+
Phony.plausible?(matches[2])
|
42
|
+
[matches[1].strip, Phony.normalize(matches[2])]
|
43
|
+
elsif Phony.plausible?(from)
|
44
|
+
[nil, Phony.normalize(from)]
|
45
|
+
else
|
46
|
+
[from.strip, nil]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_to(to)
|
51
|
+
to = [*to]
|
52
|
+
to = to.select { |phone| Phony.plausible?(phone) }
|
53
|
+
to = to.map { |phone| Phony.normalize(phone) }
|
54
|
+
|
55
|
+
to
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_content(content)
|
59
|
+
content = content.gsub(/\s{1,}/, ' ')
|
60
|
+
content = content.strip
|
61
|
+
|
62
|
+
content
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: textris
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Karol Słuszniak
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: render_anywhere
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.10
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.10
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: actionmailer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.0.0
|
41
|
+
description: Implement texter classes for sending SMS messages in similar way to how
|
42
|
+
e-mails are sent with ActionMailer-based mailers. Take advantage of e-mail proxying
|
43
|
+
and enhanced phone number parsing, among others.
|
44
|
+
email: k.sluszniak@visuality.pl
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files:
|
48
|
+
- README.md
|
49
|
+
files:
|
50
|
+
- README.md
|
51
|
+
- lib/textris.rb
|
52
|
+
- lib/textris/base.rb
|
53
|
+
- lib/textris/delivery.rb
|
54
|
+
- lib/textris/delivery/mail.rb
|
55
|
+
- lib/textris/delivery/test.rb
|
56
|
+
- lib/textris/message.rb
|
57
|
+
homepage: http://github.com/visualitypl/textris
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.2.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Simple SMS messaging gem for Rails based on concepts and conventions similar
|
81
|
+
to ActionMailer, with some extra features.
|
82
|
+
test_files: []
|