subscribed_to 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ gem "activerecord"
4
+ gem "hominid", ">= 3.0.2"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "sqlite3-ruby", :require => "sqlite3"
10
+ gem "factory_girl_rails", "1.0.1"
11
+ gem "mocha", "0.9.12"
12
+ gem "rspec-rails", "2.5.0"
13
+ gem "generator_spec"
14
+ gem "bundler", "~> 1.0.0"
15
+ gem "jeweler", "~> 1.6.0"
16
+ gem "simplecov", ">=0.4.0"
17
+ gem "hanna"
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,121 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.7)
6
+ actionpack (= 3.0.7)
7
+ mail (~> 2.2.15)
8
+ actionpack (3.0.7)
9
+ activemodel (= 3.0.7)
10
+ activesupport (= 3.0.7)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.5.0)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.14)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.7)
19
+ activesupport (= 3.0.7)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.5.0)
22
+ activerecord (3.0.7)
23
+ activemodel (= 3.0.7)
24
+ activesupport (= 3.0.7)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.7)
28
+ activemodel (= 3.0.7)
29
+ activesupport (= 3.0.7)
30
+ activesupport (3.0.7)
31
+ arel (2.0.9)
32
+ builder (2.1.2)
33
+ diff-lcs (1.1.2)
34
+ erubis (2.6.6)
35
+ abstract (>= 1.0.0)
36
+ factory_girl (1.3.3)
37
+ factory_girl_rails (1.0.1)
38
+ factory_girl (~> 1.3)
39
+ railties (>= 3.0.0)
40
+ generator_spec (0.8.3)
41
+ rails (~> 3.0)
42
+ rspec-rails
43
+ git (1.2.5)
44
+ haml (2.2.24)
45
+ hanna (0.1.12)
46
+ haml (~> 2.2.8)
47
+ rake (~> 0.8.2)
48
+ rdoc (~> 2.3.0)
49
+ hominid (3.0.2)
50
+ i18n (0.5.0)
51
+ jeweler (1.6.0)
52
+ bundler (~> 1.0.0)
53
+ git (>= 1.2.5)
54
+ rake
55
+ mail (2.2.19)
56
+ activesupport (>= 2.3.6)
57
+ i18n (>= 0.4.0)
58
+ mime-types (~> 1.16)
59
+ treetop (~> 1.4.8)
60
+ mime-types (1.16)
61
+ mocha (0.9.12)
62
+ polyglot (0.3.1)
63
+ rack (1.2.2)
64
+ rack-mount (0.6.14)
65
+ rack (>= 1.0.0)
66
+ rack-test (0.5.7)
67
+ rack (>= 1.0)
68
+ rails (3.0.7)
69
+ actionmailer (= 3.0.7)
70
+ actionpack (= 3.0.7)
71
+ activerecord (= 3.0.7)
72
+ activeresource (= 3.0.7)
73
+ activesupport (= 3.0.7)
74
+ bundler (~> 1.0)
75
+ railties (= 3.0.7)
76
+ railties (3.0.7)
77
+ actionpack (= 3.0.7)
78
+ activesupport (= 3.0.7)
79
+ rake (>= 0.8.7)
80
+ thor (~> 0.14.4)
81
+ rake (0.8.7)
82
+ rdoc (2.3.0)
83
+ rspec (2.5.0)
84
+ rspec-core (~> 2.5.0)
85
+ rspec-expectations (~> 2.5.0)
86
+ rspec-mocks (~> 2.5.0)
87
+ rspec-core (2.5.2)
88
+ rspec-expectations (2.5.0)
89
+ diff-lcs (~> 1.1.2)
90
+ rspec-mocks (2.5.0)
91
+ rspec-rails (2.5.0)
92
+ actionpack (~> 3.0)
93
+ activesupport (~> 3.0)
94
+ railties (~> 3.0)
95
+ rspec (~> 2.5.0)
96
+ simplecov (0.4.2)
97
+ simplecov-html (~> 0.4.4)
98
+ simplecov-html (0.4.5)
99
+ sqlite3 (1.3.3)
100
+ sqlite3-ruby (1.3.3)
101
+ sqlite3 (>= 1.3.3)
102
+ thor (0.14.6)
103
+ treetop (1.4.9)
104
+ polyglot (>= 0.3.1)
105
+ tzinfo (0.3.27)
106
+
107
+ PLATFORMS
108
+ ruby
109
+
110
+ DEPENDENCIES
111
+ activerecord
112
+ bundler (~> 1.0.0)
113
+ factory_girl_rails (= 1.0.1)
114
+ generator_spec
115
+ hanna
116
+ hominid (>= 3.0.2)
117
+ jeweler (~> 1.6.0)
118
+ mocha (= 0.9.12)
119
+ rspec-rails (= 2.5.0)
120
+ simplecov (>= 0.4.0)
121
+ sqlite3-ruby
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 whtt-eric
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,113 @@
1
+ = SubscribedTo
2
+
3
+ Abstraction layer for managing mailing list subscription information for your user model. It makes the basic mailing list management tasks super simple.
4
+
5
+ The gem creates callbacks on your model for <tt>after_create</tt> and <tt>after_update</tt>.
6
+
7
+ The <tt>after_create</tt> callback registers the user for the mailing list if <tt>subscribed_to_list</tt> is true (ie: the user chooses checks the "Join the mailing list" box on the registration form).
8
+
9
+ The <tt>after_update</tt> callback will update the user subscription or member details. It will either:
10
+
11
+ * Unsubscribe the user from the mailing list if they have so requested
12
+ * Subscribe the user to the list if they weren't already subscribed
13
+ * Update the user's member subscription details on the mailing list for any specified <tt>merge_vars</tt> when they change
14
+ * Do nothing if neither the subscription status nor the attributes specified in the <tt>merge_vars</tt> hash change
15
+
16
+ === Requirements
17
+
18
+ * Rails 3.x
19
+
20
+ === Supported Services
21
+
22
+ <b>MailChimp</b>
23
+
24
+ via the Hominid gem - http://github.com/terra-firma/hominid
25
+
26
+ API v1.3 - http://apidocs.mailchimp.com/1.3
27
+
28
+ * listSubscribe
29
+ * listUnsubscribe
30
+ * listUpdateMember
31
+
32
+
33
+ <b>Constant Contact</b>
34
+
35
+ Planned
36
+
37
+ == Installation
38
+
39
+ Add the gem to your Gemfile
40
+
41
+ gem "subscribed_to"
42
+
43
+ Install the gem using bundler
44
+
45
+ bundle install
46
+
47
+ Run the generator. You must specify the name of your user model.
48
+ Other options:
49
+
50
+ <tt>--skip-migration</tt>:: Do not generate the migration file to add the required column
51
+ <tt>--service=SERVICE</tt>:: Specify which mailing list service you subscribe to (currently only supports "mail_chimp")
52
+
53
+ rails generate subscribed_to:install MODEL
54
+
55
+ If you run the generator with <tt>--skip-migration</tt>, then you must be sure to to include the <tt>subscribed_to_list</tt> column in some other migration.
56
+
57
+ t.boolean :subscribed_to_list, :default => false
58
+
59
+ Be sure to run the migration before you continue.
60
+
61
+ === Initializer Configuration
62
+
63
+ After the initializer has been generated, you must set your mail service configuration options. The initializer is located at: <tt>config/initializers/subscribe_to.rb</tt>
64
+
65
+ ==== Mail Chimp
66
+
67
+ Set your API key
68
+
69
+ mail_chimp_config.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
70
+
71
+ Set up your mailing lists to subscribe users to. List names can be any valid symbol.
72
+
73
+ <tt>:id</tt>:: id of list - get this from the "Settings" page of your list
74
+ <tt>:merge_vars</tt>:: hash of merge vars on list. The key is a string which corresponds to a merge var on your mailing list. The value is a symbol corresponding to the attribute/method on the user model related to the specified merge var. It MUST at least include "EMAIL" (do not use "MERGE0").
75
+
76
+ mail_chimp_config.lists = {
77
+ :mailing_list => {
78
+ :id => "xxxxxxxx",
79
+ :merge_vars => {"FNAME" => :first_name, "LNAME" => :last_name, "EMAIL" => :email}}}
80
+
81
+ === User Model Configuration
82
+
83
+ You must enable *SubscribedTo* in your user model with <tt>subscribed_to</tt>.
84
+
85
+ The only paramter it takes is a symbol which corresponds to a list in the <tt>mail_chimp_config.lists</tt> hash.
86
+
87
+ subscribed_to :mailing_list
88
+
89
+ You may also need to specify <tt>subscribed_to_list</tt> as an accessible attribute.
90
+
91
+ attr_accessible :subscribed_to_list
92
+
93
+ === View Configuration
94
+
95
+ To get things working with the view, just include a checkbox input on your user registration/edit forms.
96
+
97
+ = f.check_box :subscribed_to_list
98
+ = f.label :subscribed_to_list, "Join the mailing list"
99
+
100
+ == Contributing to subscribed_to
101
+
102
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
103
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
104
+ * Fork the project
105
+ * Start a feature/bugfix branch
106
+ * Commit and push until you are happy with your contribution
107
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
108
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
109
+
110
+ == Copyright
111
+
112
+ Copyright (c) 2011 Eric Salczynski. See LICENSE.txt for further details.
113
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ require './lib/subscribed_to/version.rb'
16
+ Jeweler::Tasks.new do |gem|
17
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
18
+ gem.name = "subscribed_to"
19
+ gem.homepage = "http://github.com/whtt-eric/subscribed_to"
20
+ gem.license = "MIT"
21
+ gem.summary = %Q{Abstract layer for managing mailing list subscriptions}
22
+ gem.description = %Q{Abstract layer for managing mailing list subscriptions}
23
+ gem.email = "eric@wehaventthetime.com"
24
+ gem.authors = ["whtt-eric"]
25
+ gem.version = SubscribedTo::Version::STRING
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rspec/core'
31
+ require 'rspec/core/rake_task'
32
+ RSpec::Core::RakeTask.new(:spec) do |spec|
33
+ spec.pattern = FileList['spec/**/*_spec.rb']
34
+ end
35
+
36
+ task :default => :spec
37
+
38
+ require 'hanna/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "subscribed_to #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Add an initializer and migration for SubscribedTo.
3
+
4
+ Example:
5
+ rails generate subscribed_to:install User
6
+
7
+ This will create:
8
+ config/initializers/subscribed_to.rb
9
+ db/migrate/add_subscribed_to_list_to_user.rb
@@ -0,0 +1,34 @@
1
+ module SubscribedTo
2
+ module Generators #:nodoc:
3
+ class InstallGenerator < Rails::Generators::NamedBase #:nodoc:
4
+ include Rails::Generators::Migration
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ desc "Create SubscribedTo initializer and migration. Pass the name of the model to hook up with SubscribedTo."
8
+ class_option :migration, :type => :boolean, :default => true, :desc => "Include migration for required columns"
9
+ class_option :service, :type => :string, :default => "mail_chimp", :desc => "Mailing list service to connect to [mail_chimp, constant_contact]"
10
+
11
+ def self.next_migration_number(dirname)
12
+ @next_migration_number ||= Time.now.strftime("%Y%m%d%H%M%S")
13
+ end
14
+
15
+ def copy_initializer
16
+ template "subscribed_to.rb", "config/initializers/subscribed_to.rb"
17
+ end
18
+
19
+ def copy_migration
20
+ migration_template "migration.rb", "db/migrate/#{migration_name}" if options.migration?
21
+ end
22
+
23
+ private
24
+
25
+ def migration_name
26
+ "add_subscribed_to_list_to_#{table_name}"
27
+ end
28
+
29
+ def table_name
30
+ name.tableize
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ class <%= migration_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :<%= table_name.to_sym %>, :subscribed_to_list, :boolean, :default => false
4
+ end
5
+
6
+ def self.down
7
+ remove_column :<%= table_name.to_sym %>, :subscribed_to_list
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ SubscribedTo.setup do |config|
2
+ config.service = :<%= options.service.to_sym %>
3
+
4
+ <%- if options.service == "mail_chimp" -%>
5
+ config.mail_chimp do |mail_chimp_config|
6
+ # Your MailChimp API key.
7
+ mail_chimp_config.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
8
+
9
+ # A hash of mailing lists to subscribe users to.
10
+ # List names can be any valid symbol.
11
+ #
12
+ # Required:
13
+ # :id - id of list
14
+ # :merge_vars - hash of merge vars on list, MUST at least include "EMAIL" (do not use "MERGE0")
15
+ mail_chimp_config.lists = {
16
+ :mailing_list => {
17
+ :id => "xxxxxxxx",
18
+ :merge_vars => {"FNAME" => :first_name, "LNAME" => :last_name, "EMAIL" => :email}}}
19
+ end
20
+ <%- end -%>
21
+ end
@@ -0,0 +1,29 @@
1
+ module SubscribedTo
2
+ module MailChimp
3
+ class Config < Hash #:nodoc:
4
+ # Creates an accessor that simply sets and reads a key in the hash:
5
+ # Borrowed from Warden: https://github.com/hassox/warden/blob/master/lib/warden/config.rb
6
+ def self.hash_accessor(*names) #:nodoc:
7
+ names.each do |name|
8
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
9
+ def #{name}
10
+ self[:#{name}]
11
+ end
12
+
13
+ def #{name}=(value)
14
+ self[:#{name}] = value
15
+ end
16
+ METHOD
17
+ end
18
+ end
19
+
20
+ hash_accessor :api_key, :lists
21
+
22
+ def initialize(config = {})
23
+ merge!(config)
24
+ self[:api_key] ||= nil
25
+ self[:lists] ||= {}
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,51 @@
1
+ require 'subscribed_to/mail_chimp/config'
2
+ require 'hominid'
3
+
4
+ module SubscribedTo
5
+ # Module for MailChimp subscription interaction
6
+ module MailChimp
7
+ module InstanceMethods
8
+ private
9
+
10
+ # Subscribe the user to the mailing list
11
+ def subscribe_to_list #:doc:
12
+ merge_vars = self.class.merge_vars.dup
13
+
14
+ if subscribed_to_list
15
+ h = Hominid::API.new(SubscribedTo.mail_chimp_config.api_key)
16
+ h.list_subscribe(self.class.list_id, self.email, merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) })
17
+ end
18
+ rescue Hominid::APIError => e
19
+ Rails.logger.warn e
20
+ end
21
+
22
+ # Update attributes of existing member
23
+ def update_list_member #:doc:
24
+ config = SubscribedTo.mail_chimp_config
25
+ merge_vars = self.class.merge_vars.dup
26
+
27
+ # only do the update if either the subscription preference has changed (the user wants to be (un)subscribed),
28
+ # or if one of the attributes in mail_chimp_config.merge_vars has changed
29
+ if !(self.changed & merge_vars.collect { |key, method| method.to_s }.push("subscribed_to_list")).empty?
30
+ api_key = config.api_key
31
+ list_id = self.class.list_id
32
+ email_attr = merge_vars["EMAIL"]
33
+ subscribed_email = self.changed.include?(email_attr.to_s) ? changed_attributes[email_attr.to_s] : self.send(email_attr)
34
+ h = Hominid::API.new(api_key)
35
+
36
+ if self.changed.include?("subscribed_to_list")
37
+ if !subscribed_to_list
38
+ h.list_unsubscribe(list_id, subscribed_email)
39
+ else
40
+ h.list_subscribe(list_id, subscribed_email, merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) })
41
+ end
42
+ elsif subscribed_to_list && !(self.changed & merge_vars.collect { |key, method| method.to_s }).empty?
43
+ h.listUpdateMember(list_id, subscribed_email, merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) })
44
+ end
45
+ end
46
+ rescue Hominid::APIError => e
47
+ Rails.logger.warn e
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ module SubscribedTo
2
+ module Version #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 2
5
+ PATCH = 0
6
+ BUILD = nil
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
9
+ end
10
+ end
@@ -0,0 +1,81 @@
1
+ require 'rails'
2
+ require 'active_record'
3
+ require 'subscribed_to/mail_chimp'
4
+
5
+ module SubscribedTo
6
+ # Mailing list service to interact with.
7
+ # Options: :mail_chimp, :constant_contact
8
+ # Currently only supports Mail Chimp
9
+ mattr_accessor :service
10
+ @@service = :mail_chimp
11
+
12
+ mattr_reader :mail_chimp_config
13
+ @@mail_chimp_config = nil
14
+
15
+ # Set up SubscribedTo
16
+ def self.setup
17
+ yield self
18
+ end
19
+
20
+ # Sets Mail Chimp configuration using a block
21
+ #
22
+ # Example configuration:
23
+ # SubscribedTo.setup do |config|
24
+ # config.service = :mail_chimp
25
+ #
26
+ # config.mail_chimp do |mail_chimp_config|
27
+ # mail_chimp_config.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
28
+ # mail_chimp_config.lists = {:mailing_list => {:id => "123456", :merge_vars => {"FNAME" => :first_name}
29
+ # end
30
+ # end
31
+ def self.mail_chimp(&block)
32
+ @@mail_chimp_config = SubscribedTo::MailChimp::Config.new
33
+ block.call @@mail_chimp_config
34
+ end
35
+
36
+ def self.included(base) #:nodoc:
37
+ base.send :extend, ClassMethods
38
+ end
39
+
40
+ module ClassMethods
41
+ # Enable *SubscribedTo* in your user model.
42
+ # The only paramter it takes is a symbol which corresponds to a list in the <tt>mail_chimp_config.lists</tt> hash.
43
+ # subscribed_to :mailing_list
44
+ def subscribed_to(id)
45
+ include InstanceMethods
46
+ include MailChimp::InstanceMethods if SubscribedTo.service == :mail_chimp
47
+
48
+ @list_key = id.to_sym
49
+
50
+ class_eval do
51
+ after_create :subscribe_to_list
52
+ after_update :update_list_member
53
+ end
54
+ end
55
+
56
+ # Returns the list id for the class as defined in mail_chimp
57
+ def list_id
58
+ SubscribedTo.mail_chimp_config.lists[@list_key][:id]
59
+ end
60
+
61
+ # Returns the hash of merge vars for the class as defined in mail_chimp
62
+ def merge_vars
63
+ SubscribedTo.mail_chimp_config.lists[@list_key][:merge_vars]
64
+ end
65
+ end
66
+
67
+ # Provides instance methods which should be overwritten in service modules
68
+ module InstanceMethods
69
+ private
70
+
71
+ # Override in MailChimp module
72
+ def subscribe_to_list
73
+ end
74
+
75
+ # Override in MailChimp module
76
+ def update_list_member
77
+ end
78
+ end
79
+ end
80
+
81
+ ActiveRecord::Base.send :include, SubscribedTo
@@ -0,0 +1,43 @@
1
+ class User < ActiveRecord::Base
2
+ subscribed_to :mailing_list
3
+ end
4
+
5
+ class MailChimpUser < User
6
+ subscribed_to :mailing_list
7
+
8
+ attr_accessor :callback_result
9
+
10
+ # Stubbed for testing
11
+ def subscribe_to_list
12
+ if subscribed_to_list
13
+ merge_vars = self.class.merge_vars.dup
14
+
15
+ # use hominid to subscribe user
16
+ self.callback_result = "Subscribed with: #{merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) }.values.join(", ")}"
17
+ else # mocked for test -- subscribed_to_list normally doesn't do anything if !subscribed_to_list
18
+ self.callback_result = "Not Subscribed"
19
+ end
20
+ end
21
+
22
+ # Stubbed for testing
23
+ def update_list_member
24
+ merge_vars = self.class.merge_vars.dup
25
+
26
+ if !(self.changed & merge_vars.collect { |key, method| method.to_s }.push("subscribed_to_list")).empty?
27
+ if self.changed.include?("subscribed_to_list")
28
+ if !subscribed_to_list
29
+ # use hominid to unsubscribe user
30
+ self.callback_result = "Unsubscribed"
31
+ else
32
+ # use hominid to subscribe user
33
+ self.callback_result = "Subscribed with: #{merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) }.values.join(", ")}"
34
+ end
35
+ elsif subscribed_to_list && !(self.changed & merge_vars.collect { |key, method| method.to_s }).empty?
36
+ # use hominid to update user
37
+ self.callback_result = "Updated with: #{merge_vars.each { |key, method| merge_vars[key] = self.send(method.to_sym) }.values.join(", ")}"
38
+ end
39
+ else # mocked for test -- update_list_member normally doesn't do anything in this case
40
+ self.callback_result = "Nothing updated"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: subscribed_to.sqlite3
4
+
5
+ mysql:
6
+ adapter: mysql
7
+ hostname: localhost
8
+ username: root
9
+ password:
10
+ database: subscribed_to
11
+
12
+ postgresql:
13
+ adapter: postgresql
14
+ hostname: localhost
15
+ username: postgres
16
+ password:
17
+ database: subscribed_to
@@ -0,0 +1,15 @@
1
+ Factory.define :subscribed_user, :class => User do |u|
2
+ u.first_name "Eric"
3
+ u.last_name "Salczynski"
4
+ u.email "eric@wehaventthetime.com"
5
+ u.subscribed_to_list true
6
+ u.password "abc123"
7
+ end
8
+
9
+ Factory.define :non_subscribed_user, :class => User do |u|
10
+ u.first_name "Ashley"
11
+ u.last_name "Beasy"
12
+ u.email "ashley@wehaventthetime.com"
13
+ u.subscribed_to_list false
14
+ u.password "abc123"
15
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+ require "action_controller"
3
+ require "generator_spec/test_case"
4
+ require 'generators/subscribed_to/install_generator'
5
+
6
+ describe SubscribedTo::Generators::InstallGenerator do
7
+ include GeneratorSpec::TestCase
8
+ destination File.expand_path("../../../tmp", __FILE__)
9
+
10
+ before(:all) { prepare_destination }
11
+
12
+ context "when run with default options" do
13
+ before(:all) { run_generator %w(User) }
14
+
15
+ it "should create an initializer" do
16
+ assert_file "config/initializers/subscribed_to.rb", /config.service = :mail_chimp/
17
+ end
18
+
19
+ it "should create a migration" do
20
+ assert_file "db/migrate/#{SubscribedTo::Generators::InstallGenerator.next_migration_number("")}_add_subscribed_to_list_to_users.rb"
21
+ end
22
+ end
23
+
24
+ context "when run with --skip-migration" do
25
+ before(:all) do
26
+ prepare_destination
27
+ run_generator %w(User --skip-migration)
28
+ end
29
+
30
+ it "should not create a migration" do
31
+ assert_no_file "db/migrate/#{SubscribedTo::Generators::InstallGenerator.next_migration_number("")}_add_subscribed_to_list_to_users.rb"
32
+ end
33
+ end
34
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,9 @@
1
+ ActiveRecord::Schema.define :version => 0 do
2
+ create_table :users, :force => true do |t|
3
+ t.string :first_name
4
+ t.string :last_name
5
+ t.string :email
6
+ t.boolean :subscribed_to_list
7
+ t.string :password
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'rspec'
7
+ require 'factory_girl'
8
+ require 'subscribed_to'
9
+
10
+ # Requires supporting files with custom matchers and macros, etc,
11
+ # in ./support/ and its subdirectories.
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
+
14
+ RSpec.configure do |config|
15
+ config.mock_with :mocha
16
+ end
17
+
18
+ ENV['DB'] ||= 'sqlite3'
19
+
20
+ database_yml = File.expand_path('../database.yml', __FILE__)
21
+ if File.exists?(database_yml)
22
+ active_record_configuration = YAML.load_file(database_yml)[ENV['DB']]
23
+
24
+ ActiveRecord::Base.establish_connection(active_record_configuration)
25
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "log", "debug.log"))
26
+
27
+ ActiveRecord::Base.silence do
28
+ ActiveRecord::Migration.verbose = false
29
+
30
+ load('schema.rb')
31
+ Dir["#{File.dirname(__FILE__)}/app/**/*.rb"].each {|f| load f}
32
+ Dir["#{File.dirname(__FILE__)}/factories/*.rb"].each {|f| load f}
33
+ end
34
+
35
+ else
36
+ raise "Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.sample"
37
+ end
38
+
39
+ Rails.logger = Logger.new(File.join(File.dirname(__FILE__), "log", "debug.log"))
40
+
41
+ def clean_database!
42
+ models = [User]
43
+ models.each do |model|
44
+ ActiveRecord::Base.connection.execute "DELETE FROM #{model.table_name}"
45
+ end
46
+ end
47
+
48
+ clean_database!
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubscribedTo::MailChimp::Config do
4
+ before(:each) { @config = SubscribedTo::MailChimp::Config.new }
5
+
6
+ it "should behave like a hash" do
7
+ @config[:foo] = :bar
8
+ @config[:foo].should eq :bar
9
+ end
10
+
11
+ it "should provide hash accessors" do
12
+ @config.api_key = "1234567890"
13
+ @config[:api_key].should eq "1234567890"
14
+ @config[:api_key] = "0987654321"
15
+ @config.api_key.should eq "0987654321"
16
+ end
17
+
18
+ it "should merge given options on initialization" do
19
+ SubscribedTo::MailChimp::Config.new(:foo => :bar)[:foo].should eq :bar
20
+ end
21
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'hominid'
3
+
4
+ describe SubscribedTo::MailChimp do
5
+ before(:each) do
6
+ SubscribedTo.mail_chimp do |config|
7
+ config.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
8
+ config.lists = {:mailing_list => {:id => "123456", :merge_vars => {"FNAME" => :first_name, "LNAME" => :last_name, "EMAIL" => :email}}}
9
+ end
10
+ end
11
+
12
+ context "for a new user" do
13
+ it "should subscribe the user" do
14
+ @user = MailChimpUser.create(Factory.attributes_for(:subscribed_user))
15
+ @user.callback_result.should eq "Subscribed with: Eric, Salczynski, eric@wehaventthetime.com"
16
+ end
17
+
18
+ it "should not subscribe the user" do
19
+ @user = MailChimpUser.create(Factory.attributes_for(:non_subscribed_user))
20
+ @user.callback_result.should eq "Not Subscribed"
21
+ end
22
+ end
23
+
24
+ context "for an existing user" do
25
+ context "who is not subscribed to the mailing list" do
26
+ before { @user = MailChimpUser.create(Factory.attributes_for(:non_subscribed_user)) }
27
+
28
+ it "should subscribe the user" do
29
+ @user.update_attributes({:subscribed_to_list => true})
30
+ @user.callback_result.should eq "Subscribed with: #{[@user.first_name, @user.last_name, @user.email].join(", ")}"
31
+ end
32
+ end
33
+
34
+ context "who is subscribed to the mailing list" do
35
+ before(:each) { @user = MailChimpUser.create(Factory.attributes_for(:subscribed_user)) }
36
+
37
+ it "should unsubscribe the user" do
38
+ @user.update_attributes({:subscribed_to_list => false})
39
+ @user.callback_result.should eq "Unsubscribed"
40
+ end
41
+
42
+ it "should update list member attributes for the user" do
43
+ @user.update_attributes({:first_name => "Ed", :last_name => "Salczynski", :email => "ed@whtt.me"})
44
+ @user.callback_result.should eq "Updated with: Ed, Salczynski, ed@whtt.me"
45
+ end
46
+
47
+ it "should not update list member when attributes not defined in merge vars are changed" do
48
+ @user.update_attributes({:password => "zyx321"})
49
+ @user.callback_result.should eq "Nothing updated"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe SubscribedTo do
4
+ it "should yield self on setup" do
5
+ SubscribedTo.setup do |config|
6
+ config.should eq SubscribedTo
7
+ end
8
+ end
9
+
10
+ it "should configure MailChimp through a block" do
11
+ SubscribedTo.mail_chimp do |config|
12
+ config.should be_an_instance_of SubscribedTo::MailChimp::Config
13
+ config.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
14
+ config.lists = {:mailing_list => {:id => "123456", :merge_vars => {"FNAME" => :first_name}}}
15
+ end
16
+
17
+ SubscribedTo.mail_chimp_config.api_key.should eq "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us1"
18
+ SubscribedTo.mail_chimp_config.lists.should eq :mailing_list => {:id => "123456", :merge_vars => {"FNAME" => :first_name}}
19
+ end
20
+
21
+ it "should include the default instance methods" do
22
+ User.included_modules.should include SubscribedTo::InstanceMethods
23
+ end
24
+
25
+ it "should add subscribe and update methods to the callback chain" do
26
+ @user = Factory.build(:subscribed_user)
27
+ @user.expects(:subscribe_to_list).once
28
+ @user.save
29
+
30
+ @user.first_name = "Edward"
31
+ @user.expects(:update_list_member).once
32
+ @user.save
33
+ end
34
+
35
+ # the default service is MailChimp
36
+ context "for MailChimp" do
37
+ it "should include the MailChimp instance methods" do
38
+ User.included_modules.should include SubscribedTo::MailChimp::InstanceMethods
39
+ end
40
+
41
+ it "should provide the class with list_id and merge_vars methods" do
42
+ SubscribedTo.mail_chimp do |config|
43
+ config.lists = {:mailing_list => {:id => "123456", :merge_vars => {"FNAME" => :first_name}}}
44
+ end
45
+
46
+ User.list_id.should eq "123456"
47
+ User.merge_vars.should eq "FNAME" => :first_name
48
+ end
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: subscribed_to
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.0
6
+ platform: ruby
7
+ authors:
8
+ - whtt-eric
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-18 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: hominid
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 3.0.2
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: sqlite3-ruby
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: factory_girl_rails
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - "="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.0.1
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: mocha
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - "="
66
+ - !ruby/object:Gem::Version
67
+ version: 0.9.12
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec-rails
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - "="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.5.0
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: generator_spec
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
94
+ name: bundler
95
+ requirement: &id008 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ~>
99
+ - !ruby/object:Gem::Version
100
+ version: 1.0.0
101
+ type: :development
102
+ prerelease: false
103
+ version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: jeweler
106
+ requirement: &id009 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: 1.6.0
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: *id009
115
+ - !ruby/object:Gem::Dependency
116
+ name: simplecov
117
+ requirement: &id010 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 0.4.0
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: *id010
126
+ - !ruby/object:Gem::Dependency
127
+ name: hanna
128
+ requirement: &id011 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: "0"
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: *id011
137
+ description: Abstract layer for managing mailing list subscriptions
138
+ email: eric@wehaventthetime.com
139
+ executables: []
140
+
141
+ extensions: []
142
+
143
+ extra_rdoc_files:
144
+ - LICENSE.txt
145
+ - README.rdoc
146
+ files:
147
+ - .document
148
+ - .rspec
149
+ - Gemfile
150
+ - Gemfile.lock
151
+ - LICENSE.txt
152
+ - README.rdoc
153
+ - Rakefile
154
+ - lib/generators/subscribed_to/USAGE
155
+ - lib/generators/subscribed_to/install_generator.rb
156
+ - lib/generators/subscribed_to/templates/migration.rb
157
+ - lib/generators/subscribed_to/templates/subscribed_to.rb
158
+ - lib/subscribed_to.rb
159
+ - lib/subscribed_to/mail_chimp.rb
160
+ - lib/subscribed_to/mail_chimp/config.rb
161
+ - lib/subscribed_to/version.rb
162
+ - spec/app/models/user.rb
163
+ - spec/database.yml.example
164
+ - spec/factories/users.rb
165
+ - spec/generators/install_generator_spec.rb
166
+ - spec/schema.rb
167
+ - spec/spec_helper.rb
168
+ - spec/subscribed_to/mail_chimp/config_spec.rb
169
+ - spec/subscribed_to/mail_chimp_spec.rb
170
+ - spec/subscribed_to_spec.rb
171
+ has_rdoc: true
172
+ homepage: http://github.com/whtt-eric/subscribed_to
173
+ licenses:
174
+ - MIT
175
+ post_install_message:
176
+ rdoc_options: []
177
+
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ none: false
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ hash: 1335917726808869519
186
+ segments:
187
+ - 0
188
+ version: "0"
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.6.2
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: Abstract layer for managing mailing list subscriptions
202
+ test_files: []
203
+