welcome_cycle 0.0.4

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.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ *.tmproj
7
+ nbproject
8
+ .DS_Store
9
+ log/*.log
10
+ tmp/**/*
11
+ bin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in welcome_cycle.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # welcome_cycle
2
+
3
+ `welcome_cycle` is a ruby gem to help you send out a cycle of emails. Specifically when new users sign up to your app.
4
+
5
+ ## Gemfile
6
+ gem 'welcome_cycle'
7
+ bundle install
8
+
9
+ ## Install
10
+ rails generate welcome_cycle:install
11
+
12
+ **Creates:**
13
+
14
+ `config/initializers/welcome_cycle.rb` - Defines config and your emails.
15
+
16
+ `app/mailers/welcome_cycle_mailer.rb` - Mailer methods for each email, each one is passed the recipient object.
17
+
18
+ ## Config
19
+
20
+ The configure block should be specified at the top of `welcome_cycle.rb`
21
+
22
+ WelcomeCycle.configure do |c|
23
+ c.base_class = Subscription
24
+ c.welcome_cycle_start_date = :trial_started_at
25
+ c.welcome_cycle_end_date = :trial_ends_at
26
+ c.before { run_something_special }
27
+ c.after { run_something_special }
28
+ end
29
+
30
+ **base_class** - The base model in your app to query for email recipients. (E.g Organisation, Subscription, User, Account, etc.)
31
+
32
+ **welcome_cycle_start_date** - The date/datetime field that determines the start of your welcome cycle. (If you want to send email 'n' days after the start.)
33
+
34
+ **welcome_cycle_end_date** - The date/datetime field that determines the end of the welcome cycle. (If you want to send emails 'n' days around the end.)
35
+
36
+ **before** - An optional callback to run before all emails are sent.
37
+
38
+ **after** - An optional callback to run after all emails are sent.
39
+
40
+
41
+ ## Defining new emails
42
+
43
+ rails generate welcome_cycle:email name_for_your_email_here
44
+
45
+ The above generator will add an email definition to `welcome_cycle.rb`, add the mailer method to `welcome_cycle_mailer.rb` and create the corresponding text and html erb templates.
46
+
47
+ ### Options for each email
48
+
49
+ **days_into_cycle** – The days on which you would like the email to be sent after signing up. E.g.: 3 = Three days after the sign up.
50
+
51
+ **days_offset_from_cycle_end** - The days on which you like the email to go out around the cycle/trial end.
52
+
53
+ * positive numbers: Number of days *before* the welcome cycle ends.
54
+ * negative number: Number of days *after* the welcome cycle ends.
55
+
56
+ **scope** - An optional arel chain that allows you restrict the recipients to any conditions you like.
57
+
58
+ * With some simple conditions you can easily set up email variations. E.g. have they performed a certain task? Have they subscribed? Etc.
59
+
60
+ You **must** specify days_into_cycle or days_offset_from_cycle_end.
61
+
62
+ ### Example email definitions:
63
+
64
+ WelcomeCycle::Email.new("We miss you") do
65
+ days 7, 14, 21
66
+ scope do
67
+ where('last_login = ?', nil)
68
+ end
69
+ end
70
+
71
+ WelcomeCycle::Email.new("Trial ends soon!") do
72
+ days -5
73
+ scope do
74
+ where(:subscribed_at => false)
75
+ end
76
+ end
77
+
78
+ ##
79
+
80
+ ## Sending the emails
81
+ Set your favourite scheduler to run the WelcomeCycle::Driver.run daily. E.g. using CRON to send them everyday at 6am:
82
+
83
+ 0 6 * * * cd /path/to/you/app && rails runner -e production 'WelcomeCycle::Driver.run'
84
+
85
+ ## Notes
86
+ 1. The email templates and corresponding methods live inside your app.
87
+ 2. Ironically welcome_cycle is not designed to send an actual welcome_email! You probably want do that immediately when people sign-up. Feel free to use the provided mailer class.
88
+ 3. We'll try our best to stick to semantic versioning (http://semver.org/)
89
+
90
+ ## TODO
91
+ * Work out a clean way of ignoring the initializer unless rails runner is being used.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,41 @@
1
+ module WelcomeCycle
2
+ module Generators
3
+ class EmailGenerator < Rails::Generators::NamedBase
4
+
5
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+
7
+ def register_new_mail
8
+ append_to_file 'config/initializers/welcome_cycle.rb' do
9
+ <<-EOS
10
+
11
+
12
+ WelcomeCycle::Email.new("#{file_name.gsub(/_/, ' ').capitalize}") do
13
+ days_into_cycle 5, 10 # Send on 5 and 10 days into trial
14
+ days_offset_from_cycle_end -5, 5 # Send 5 days before and 5 days after the cycle ends
15
+ scope do
16
+ # send if these Arel conditions are met
17
+ end
18
+ end
19
+ EOS
20
+ end
21
+ end
22
+
23
+ def add_new_mailer_action
24
+ gsub_file 'app/mailers/welcome_cycle_mailer.rb', '# your actions here', ''
25
+ inject_into_class 'app/mailers/welcome_cycle_mailer.rb', WelcomeCycleMailer do
26
+ <<-EOS
27
+
28
+ def #{file_name}(recipient)
29
+ mail(:to => recipient.email, :subject => 'Your subject here')
30
+ end
31
+ EOS
32
+ end
33
+ end
34
+
35
+ def add_new_mailer_templates
36
+ create_file "app/views/welcome_cycle_mailer/#{file_name}.text.erb"
37
+ create_file "app/views/welcome_cycle_mailer/#{file_name}.html.erb"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ module WelcomeCycle
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+
7
+ def copy_welcome_cycle_mailer
8
+ copy_file 'welcome_cycle_mailer.rb', File.join('app','mailers','welcome_cycle_mailer.rb')
9
+ end
10
+
11
+ def copy_email_list
12
+ copy_file 'welcome_cycle.rb', File.join('config','initializers','welcome_cycle.rb')
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ WelcomeCycle.configure do |c|
2
+ c.base_class = Subscription
3
+ c.welcome_cycle_start_date = :trial_started_at
4
+ c.welcome_cycle_end_date = :trial_ends_at
5
+ end
6
+
7
+ # run 'rails generate welcome_cycle:email name_for_your_email_here' to add new welcome cycle emails
@@ -0,0 +1,3 @@
1
+ class WelcomeCycleMailer < ActionMailer::Base
2
+ # your actions here
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'singleton'
2
+
3
+ require "welcome_cycle/version"
4
+ require "welcome_cycle/driver"
5
+ require "welcome_cycle/email"
6
+ require "welcome_cycle/email_register"
7
+ require "welcome_cycle/config"
8
+
9
+ module WelcomeCycle
10
+
11
+ class << self
12
+ attr_accessor :config
13
+ end
14
+
15
+ def self.configure
16
+ self.config ||= WelcomeCycle::Config.new
17
+ yield(config)
18
+ end
19
+
20
+ end
@@ -0,0 +1,22 @@
1
+ module WelcomeCycle
2
+
3
+ class Config
4
+ attr_accessor :base_class, :welcome_cycle_start_date, :welcome_cycle_end_date
5
+ attr_reader :before_run, :after_run
6
+
7
+ def initialize
8
+ @welcome_cycle_start_date = :trial_stared_at
9
+ @welcome_cycle_end_date = :trial_ends_at
10
+ end
11
+
12
+ def before(&block)
13
+ @before_run = block
14
+ end
15
+
16
+ def after(&block)
17
+ @after_run = block
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,11 @@
1
+ module WelcomeCycle
2
+ class Driver
3
+ def self.run
4
+ raise 'WelcomeCycle is not configured! See the README config section for help.' if WelcomeCycle.config.nil?
5
+ raise "You must set the 'base_class' option. See README config section." if WelcomeCycle.config.base_class.nil?
6
+ WelcomeCycle.config.before_run.call if WelcomeCycle.config.before_run
7
+ WelcomeCycle::EmailRegister.instance.emails.each { |e| e.send_to_recipients! }
8
+ WelcomeCycle.config.after_run.call if WelcomeCycle.config.after_run
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,78 @@
1
+ module WelcomeCycle
2
+
3
+ class Email
4
+
5
+ def initialize(name, &block)
6
+ @name = name
7
+ instance_eval &block
8
+ raise "You must specify at least one day to send this email by specifying 'days_into_cycle' and/or 'days_offset_from_cycle_end'" if @days_into_cycle.nil? && @days_offset_from_cycle_end.nil?
9
+ WelcomeCycle::EmailRegister.instance << self
10
+ end
11
+
12
+ def days_into_cycle(*days)
13
+ raise ArgumentError, "'days_into_cycle' can only contain positive numbers" if days.detect { |d| d <= 0 }
14
+ raise "When specifying 'days_into_cycle' you must set the 'welcome_cycle_start_date'. See README config section" if WelcomeCycle.config.welcome_cycle_start_date.nil?
15
+ @days_into_cycle = days
16
+ end
17
+
18
+ def days_offset_from_cycle_end(*days)
19
+ raise "When specifying 'days_offset_from_cycle_end' you must set the 'welcome_cycle_end_date' config section" if WelcomeCycle.config.welcome_cycle_end_date.nil?
20
+ @days_offset_from_cycle_end = days
21
+ end
22
+
23
+ def scope(&block)
24
+ @scope_chain = block
25
+ end
26
+
27
+ def send_to_recipients!
28
+ recipients.each { |r| deliver(r) }
29
+ end
30
+
31
+ def recipients
32
+ recipients = WelcomeCycle.config.base_class
33
+ recipients = recipients.where(date_conditions)
34
+ @scope_chain.nil? ? recipients.all : recipients.instance_eval(&@scope_chain)
35
+ end
36
+
37
+ def deliver(r)
38
+ if defined?(Delayed) && (defined?(Delayed::Job) || defined?(Delayed::Worker))
39
+ deliver_via_delayed_job(r)
40
+ else
41
+ deliver_directly(r)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def deliver_via_delayed_job(r)
48
+ WelcomeCycleMailer.delay.send(template_name, r)
49
+ end
50
+
51
+ def deliver_directly(r)
52
+ if mail_message_obj = WelcomeCycleMailer.send(template_name, r)
53
+ mail_message_obj.deliver
54
+ else
55
+ raise "Failed to create Mail::Message object from the current template name '#{template_name}'. Check it is specified in your WelcomeCycleMailer."
56
+ end
57
+ end
58
+
59
+ def template_name
60
+ @name.downcase.gsub(/\s/, '_')
61
+ end
62
+
63
+ def date_conditions
64
+ conditions = ['']
65
+ [[WelcomeCycle.config.welcome_cycle_start_date, @days_into_cycle], [WelcomeCycle.config.welcome_cycle_end_date, @days_offset_from_cycle_end]].each do |field_name, cycle_days|
66
+ next if cycle_days.nil?
67
+ cycle_days.each do |day_in_cycle|
68
+ conditions[0] << " OR " unless conditions[0].empty?
69
+ conditions[0] << "date(`#{WelcomeCycle.config.base_class.table_name}`.`#{field_name}`) = ?"
70
+ conditions << Time.now.utc.to_date - day_in_cycle # Positive: 6th-5.days = 1st / Negative: 25th--5.days = 30th
71
+ end
72
+ end
73
+ conditions
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,21 @@
1
+ module WelcomeCycle
2
+ class EmailRegister
3
+
4
+ include Singleton
5
+
6
+ attr_accessor :emails
7
+
8
+ def initialize
9
+ @emails = []
10
+ end
11
+
12
+ def <<(email)
13
+ @emails << email
14
+ end
15
+
16
+ def each
17
+ @emails.each { |email| yield(email) }
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module WelcomeCycle
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'welcome_cycle'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Config do
4
+
5
+ subject { WelcomeCycle::Config.new }
6
+
7
+ describe "new config object" do
8
+ it 'has sensible defaults for the welcome cycle start and end dates' do
9
+ subject.welcome_cycle_start_date.should eq(:trial_stared_at)
10
+ subject.welcome_cycle_end_date.should eq(:trial_ends_at)
11
+ end
12
+ end
13
+
14
+ describe "attributes" do
15
+ it 'allows you to set :base_class' do
16
+ subject.base_class = 'SomeClass'
17
+ subject.base_class.should eq('SomeClass')
18
+ end
19
+ it 'allows you to set :welcome_cycle_start_date' do
20
+ subject.welcome_cycle_start_date = :signed_up_at
21
+ subject.welcome_cycle_start_date.should eq(:signed_up_at)
22
+ end
23
+ it 'allows you to set :welcome_cycle_end_date' do
24
+ subject.welcome_cycle_end_date = :close_at
25
+ subject.welcome_cycle_end_date.should eq(:close_at)
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Driver do
4
+
5
+ describe "::run" do
6
+ let(:email1) { mock('email 1').as_null_object }
7
+ let(:email2) { mock('email 1').as_null_object }
8
+
9
+ context "when WelcomeCycle has not been configured" do
10
+ it 'raises an error telling you to configure it' do
11
+ lambda { WelcomeCycle::Driver.run }.should raise_error('WelcomeCycle is not configured! See the README config section for help.')
12
+ end
13
+ end
14
+
15
+ context "when no base_class is configured" do
16
+ before { WelcomeCycle.configure {} }
17
+ it 'raises an error telling you to set the base class' do
18
+ lambda { WelcomeCycle::Driver.run }.should raise_error("You must set the 'base_class' option. See README config section.")
19
+ end
20
+ end
21
+
22
+ context "when configured with a base class" do
23
+ before do
24
+ WelcomeCycle.configure { |c| c.base_class = mock('class') }
25
+ WelcomeCycle::EmailRegister.instance << email1
26
+ WelcomeCycle::EmailRegister.instance << email2
27
+ end
28
+
29
+ it 'calls #send_to_recipients! on each email in the register' do
30
+ email1.should_receive(:send_to_recipients!)
31
+ email2.should_receive(:send_to_recipients!)
32
+ WelcomeCycle::Driver.run
33
+ end
34
+ end
35
+
36
+ describe 'callbacks' do
37
+ it 'calls the before_run callback if one is set' do
38
+ WelcomeCycle.configure { |c| c.before {} }
39
+ WelcomeCycle.config.before_run.should_receive(:call)
40
+ WelcomeCycle::Driver.run
41
+ end
42
+
43
+ it 'calls the after_run callback if one is set' do
44
+ WelcomeCycle.configure { |c| c.after {} }
45
+ WelcomeCycle.config.after_run.should_receive(:call)
46
+ WelcomeCycle::Driver.run
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::EmailRegister do
4
+
5
+ subject { WelcomeCycle::EmailRegister.instance }
6
+
7
+ after(:each) { WelcomeCycle::EmailRegister.instance.emails = [] }
8
+
9
+ describe "attributes" do
10
+ it 'allows setting/getting :emails' do
11
+ subject.emails = [1, 2, 3]
12
+ subject.emails.should eq([1, 2, 3])
13
+ end
14
+ end
15
+
16
+ describe "adding emails into the register" do
17
+ let(:email_register) { WelcomeCycle::EmailRegister.instance }
18
+ it 'stores them in an array' do
19
+ subject << "email1"
20
+ subject << "email2"
21
+ subject << "email3"
22
+ subject.emails.should eq(['email1', 'email2', 'email3'])
23
+ end
24
+ end
25
+
26
+ describe "each" do
27
+ let(:email1) { mock('email1') }
28
+ let(:email2) { mock('email2') }
29
+ let(:email3) { mock('email2') }
30
+
31
+ it 'yields the given block for each email in the register' do
32
+ subject << email1
33
+ subject << email2
34
+ subject << email3
35
+ email1.should_receive(:some_method)
36
+ email2.should_receive(:some_method)
37
+ email3.should_receive(:some_method)
38
+ subject.emails.each { |e| e.some_method }
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Email do
4
+
5
+ let(:today) { Time.now.utc.to_date }
6
+
7
+ class WelcomeCycleMailer
8
+ end
9
+
10
+ class Subscription
11
+ def self.table_name
12
+ 'organisations'
13
+ end
14
+ end
15
+
16
+ before(:each) do
17
+ WelcomeCycle.configure do |c|
18
+ c.base_class = Subscription
19
+ c.welcome_cycle_start_date = :trial_started_at
20
+ c.welcome_cycle_end_date = :trial_ends_at
21
+ end
22
+ end
23
+
24
+ subject do
25
+ WelcomeCycle::Email.new("Test email") do
26
+ days_into_cycle 1, 10, 25
27
+ scope do
28
+ where('created_at < ?', today)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#initialize" do
34
+ it 'raises an error if you do not specify any days' do
35
+ lambda { WelcomeCycle::Email.new("Test email") {} }.should raise_error("You must specify at least one day to send this email by specifying 'days_into_cycle' and/or 'days_offset_from_cycle_end'")
36
+ end
37
+ it 'adds itself into the register' do
38
+ lambda {
39
+ WelcomeCycle::Email.new("Test email") { days_into_cycle 1 }
40
+ }.should change(WelcomeCycle::EmailRegister.instance.emails, :size).by(1)
41
+ end
42
+ end
43
+
44
+ describe "#days_into_cycle" do
45
+ it 'allows you to set the days the email should be sent after the cycle begins' do
46
+ subject.days_into_cycle(1,2,3,4,5).should eq([1,2,3,4,5])
47
+ subject.days_into_cycle(1,2,3).should eq([1,2,3])
48
+ end
49
+ it 'raises an ArgumentError if passed day 0' do
50
+ lambda { subject.days_into_cycle(1, 10, 0, 25) }.should raise_error(ArgumentError, "'days_into_cycle' can only contain positive numbers")
51
+ end
52
+ it 'raises an ArgumentError if passed day a negative day' do
53
+ lambda { subject.days_into_cycle(1, -4, 25) }.should raise_error(ArgumentError, "'days_into_cycle' can only contain positive numbers")
54
+ end
55
+ context 'with no welcome_start_date set' do
56
+ before { WelcomeCycle.config.welcome_cycle_start_date = nil }
57
+ it 'raises an error' do
58
+ lambda { subject.days_into_cycle(1) }.should raise_error("When specifying 'days_into_cycle' you must set the 'welcome_cycle_start_date'. See README config section")
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#days_offset_from_cycle_end" do
64
+ it 'allows you to set the days the email should be sent, offset from the cycle beginning' do
65
+ subject.days_offset_from_cycle_end(-1,0,1).should eq([-1,0,1])
66
+ end
67
+ context 'with no welcome_cycle_end_date set' do
68
+ before { WelcomeCycle.config.welcome_cycle_end_date = nil }
69
+ it 'raises an error' do
70
+ lambda { subject.days_offset_from_cycle_end(1, -4, 25)}.should raise_error("When specifying 'days_offset_from_cycle_end' you must set the 'welcome_cycle_end_date' config section")
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#scope' do
76
+ it 'allows you to set a further scope for the email recipients' do
77
+ subject.scope do
78
+ where('1=1')
79
+ end.should be_a(Proc)
80
+ end
81
+ end
82
+
83
+ describe '#send_to_recipients!' do
84
+ let(:r1) { mock 'mock recipient 1' }
85
+ let(:r2) { mock 'mock recipient 2' }
86
+ let(:r3) { mock 'mock recipient 3' }
87
+
88
+ before { subject.stub(:recipients).and_return([r1, r2, r3]) }
89
+
90
+ it 'delivers the email to each recipient' do
91
+ subject.should_receive(:deliver).with(r1)
92
+ subject.should_receive(:deliver).with(r2)
93
+ subject.should_receive(:deliver).with(r3)
94
+ subject.send_to_recipients!
95
+ end
96
+ end
97
+
98
+ describe "#recipients" do
99
+ let(:mock_orgs) { mock "Orgs" }
100
+ context "with the email set to go out on day 5 and 10 of the welcome cycle" do
101
+ let(:email) { WelcomeCycle::Email.new("Test email") { days_into_cycle(5, 10) } }
102
+ it 'queries the base class for all the records that started the welcome cycle 5 or 10 days ago' do
103
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_started_at`) = ? OR date(`organisations`.`trial_started_at`) = ?", today - 5, today - 10]).and_return(mock_orgs)
104
+ mock_orgs.should_receive(:all)
105
+ email.recipients
106
+ end
107
+ end
108
+ context "with the email set to go out 9 and 3 days before the welcome cycle ends" do
109
+ let(:email) { WelcomeCycle::Email.new("Test email") { days_offset_from_cycle_end(-9, -3) } }
110
+ it 'queries the base class for all the records that are 5/3 days away from ending the welcome cycle' do
111
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_ends_at`) = ? OR date(`organisations`.`trial_ends_at`) = ?", today + 9, today + 3]).and_return(mock_orgs)
112
+ mock_orgs.should_receive(:all)
113
+ email.recipients
114
+ end
115
+ end
116
+ context "with an extra Arel scope set" do
117
+ let(:email) do
118
+ WelcomeCycle::Email.new("Test email") do
119
+ days_into_cycle(3)
120
+ days_offset_from_cycle_end(-5)
121
+ scope do
122
+ active.where('1=1')
123
+ end
124
+ end
125
+ end
126
+ it "adds the extra scope to the date based query on the base_class" do
127
+ mock_active_orgs = mock 'mock active orgs'
128
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_started_at`) = ? OR date(`organisations`.`trial_ends_at`) = ?", today - 3, today + 5]).and_return(mock_orgs)
129
+ mock_orgs.should_receive(:active).and_return(mock_active_orgs)
130
+ mock_active_orgs.should_receive(:where).with('1=1')
131
+ email.recipients
132
+ end
133
+ context 'with a non-default configuration for the date fields' do
134
+ before do
135
+ WelcomeCycle.configure do |c|
136
+ c.welcome_cycle_start_date = :my_test_start_date
137
+ c.welcome_cycle_end_date = :my_test_end_date
138
+ end
139
+ end
140
+ it "queries based on the configured field names" do
141
+ mock_active_orgs = mock 'mock active orgs'
142
+ Subscription.should_receive(:where).with(["date(`organisations`.`my_test_start_date`) = ? OR date(`organisations`.`my_test_end_date`) = ?", today - 3, today + 5]).and_return(mock_orgs)
143
+ mock_orgs.should_receive(:active).and_return(mock_active_orgs)
144
+ mock_active_orgs.should_receive(:where).with('1=1')
145
+ email.recipients
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#deliver" do
152
+ let(:mock_email) { mock 'email' }
153
+ let(:mock_recipient) { mock 'recipient' }
154
+ let(:mock_dj) { mock 'delayed job' }
155
+
156
+ context 'without DelayedJob in the project' do
157
+ it 'calls deliver on the mailer template for this email passing in the recipient' do
158
+ WelcomeCycleMailer.should_receive(:test_email).with(mock_recipient).and_return(mock_email)
159
+ mock_email.should_receive(:deliver)
160
+ subject.deliver(mock_recipient)
161
+ end
162
+ end
163
+
164
+ context 'with DelayedJob in place' do
165
+ before do
166
+ module Delayed
167
+ class Job
168
+ end
169
+ end
170
+ end
171
+
172
+ it 'queues the email for delivery' do
173
+ WelcomeCycleMailer.should_receive(:delay).and_return(mock_dj)
174
+ mock_dj.should_receive(:test_email).with(mock_recipient).and_return(true)
175
+ subject.deliver(mock_recipient)
176
+ end
177
+ end
178
+ end
179
+
180
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle do
4
+
5
+ describe "::configure" do
6
+ before do
7
+ WelcomeCycle.configure do |c|
8
+ c.base_class = String
9
+ end
10
+ end
11
+
12
+ it 'sets a module attribute :config to a new WelcomeCycle::Config object and sets the attributes specified in the block given' do
13
+ WelcomeCycle.config.should be_a(WelcomeCycle::Config)
14
+ WelcomeCycle.config.base_class.should eq(String)
15
+ end
16
+
17
+ describe 'calling config more than once' do
18
+ before do
19
+ WelcomeCycle.configure do |c|
20
+ c.base_class = String
21
+ end
22
+ end
23
+ it 'does not create a new WelcomeCycle::Config object' do
24
+ WelcomeCycle::Config.should_receive(:new).never
25
+ WelcomeCycle.configure do |c|
26
+ c.base_class = Fixnum
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "welcome_cycle/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "welcome_cycle"
7
+ s.version = WelcomeCycle::VERSION
8
+ s.authors = ["Luke Brown", "Chris Stainthorpe"]
9
+ s.email = ["tsdbrown@gmail.com", "chris@randomcat.co.uk"]
10
+ s.homepage = ""
11
+ s.summary = %q{Welcome cycle code for SAAS apps}
12
+ s.description = %q{The idea behind this gem is to abstract out the logic of sending out welcome emails during a free trial.}
13
+
14
+ s.rubyforge_project = "welcome_cycle"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency(%q<rails>, [">= 3.0.10"])
22
+
23
+ s.add_development_dependency "rspec"
24
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: welcome_cycle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Luke Brown
9
+ - Chris Stainthorpe
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-02-17 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &2156475920 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.10
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2156475920
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2156475500 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2156475500
37
+ description: The idea behind this gem is to abstract out the logic of sending out
38
+ welcome emails during a free trial.
39
+ email:
40
+ - tsdbrown@gmail.com
41
+ - chris@randomcat.co.uk
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - README.md
49
+ - Rakefile
50
+ - lib/generators/welcome_cycle/email/email_generator.rb
51
+ - lib/generators/welcome_cycle/install/install_generator.rb
52
+ - lib/generators/welcome_cycle/install/templates/welcome_cycle.rb
53
+ - lib/generators/welcome_cycle/install/templates/welcome_cycle_mailer.rb
54
+ - lib/welcome_cycle.rb
55
+ - lib/welcome_cycle/config.rb
56
+ - lib/welcome_cycle/driver.rb
57
+ - lib/welcome_cycle/email.rb
58
+ - lib/welcome_cycle/email_register.rb
59
+ - lib/welcome_cycle/version.rb
60
+ - spec/spec_helper.rb
61
+ - spec/welcome_cycle/config_spec.rb
62
+ - spec/welcome_cycle/driver_spec.rb
63
+ - spec/welcome_cycle/email_register_spec.rb
64
+ - spec/welcome_cycle/email_spec.rb
65
+ - spec/welcome_cycle_spec.rb
66
+ - welcome_cycle.gemspec
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: welcome_cycle
87
+ rubygems_version: 1.8.6
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Welcome cycle code for SAAS apps
91
+ test_files:
92
+ - spec/spec_helper.rb
93
+ - spec/welcome_cycle/config_spec.rb
94
+ - spec/welcome_cycle/driver_spec.rb
95
+ - spec/welcome_cycle/email_register_spec.rb
96
+ - spec/welcome_cycle/email_spec.rb
97
+ - spec/welcome_cycle_spec.rb