sorry-rails 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 33f0f6dd7ac550d6064a8f90b428f635128a6ddd
4
- data.tar.gz: 1815b8933a345176d80fe341cbaf84aee30eb6b2
3
+ metadata.gz: 47ef1033ef828a5f626e82e9917e4b933faf134b
4
+ data.tar.gz: 468b191147aa0fe4f8609b2f3e6d7ed3cd5f5013
5
5
  SHA512:
6
- metadata.gz: 9e0b92e456690951be39ec8a8099ca0ec3b54bc659531ff8a19433df4fbd505c43fb24b0649d5cfe3925d1c6ff2c796f80abe6c7b78443bc2cb5fe11ff84ee0c
7
- data.tar.gz: 4bfa6e41064cc24117d728dc2f49ce7dd145159c5c60df0dbe19bf83bc90bbe8f63ce737c9f96439ec837d5c71d00bfb8161a6ddcc101e4032ef355a987ede33
6
+ metadata.gz: 493917af41e616934deed8ae63115eda700c7972a1e1f8ee2fca69a67cf087e79aa0ffff669ca3d74ba8f3d44bcde97465e7a909e6d0c9ccabc729d47a648ebe
7
+ data.tar.gz: f37b3b7e311b7ae90d0d75da0ef90cff99e8d2579369d7d52c40bda59e38ba69a2e51c0bf8891ab1063c11d2cf360c1df4c807679fd6b9e451fe82dff26e6e45
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .DS_Store
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,28 @@
1
+ Layout/IndentationWidth:
2
+ Width: 4
3
+
4
+ Metrics/LineLength:
5
+ Max: 200
6
+
7
+ Metrics/BlockLength:
8
+ Exclude:
9
+ - 'spec/**/*.rb'
10
+
11
+ Layout/EmptyLinesAroundBlockBody:
12
+ Exclude:
13
+ - 'spec/**/*.rb'
14
+
15
+ Layout/EmptyLinesAroundClassBody:
16
+ EnforcedStyle: empty_lines_except_namespace
17
+
18
+ Layout/EmptyLinesAroundModuleBody:
19
+ EnforcedStyle: empty_lines_except_namespace
20
+
21
+ Layout/AlignParameters:
22
+ EnforcedStyle: with_fixed_indentation
23
+
24
+ Layout/IndentHash:
25
+ EnforcedStyle: consistent
26
+
27
+ Style/GuardClause:
28
+ Enabled: false
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
4
+ - 2.4
5
+ - 2.3
6
+ script:
7
+ - bundle exec rubocop
8
+ - bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in sorry-rails.gemspec
6
+ gemspec
@@ -0,0 +1,96 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sorry-rails (0.1.2)
5
+ actionview
6
+ activesupport
7
+ hashie (~> 2.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionview (5.2.0)
13
+ activesupport (= 5.2.0)
14
+ builder (~> 3.1)
15
+ erubi (~> 1.4)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
18
+ activesupport (5.2.0)
19
+ concurrent-ruby (~> 1.0, >= 1.0.2)
20
+ i18n (>= 0.7, < 2)
21
+ minitest (~> 5.1)
22
+ tzinfo (~> 1.1)
23
+ ast (2.4.0)
24
+ builder (3.2.3)
25
+ concurrent-ruby (1.0.5)
26
+ crass (1.0.4)
27
+ diff-lcs (1.3)
28
+ erubi (1.7.1)
29
+ faker (1.8.7)
30
+ i18n (>= 0.7)
31
+ hashie (2.1.2)
32
+ i18n (1.0.1)
33
+ concurrent-ruby (~> 1.0)
34
+ jaro_winkler (1.5.1)
35
+ loofah (2.2.2)
36
+ crass (~> 1.0.2)
37
+ nokogiri (>= 1.5.9)
38
+ mini_portile2 (2.3.0)
39
+ minitest (5.11.3)
40
+ nokogiri (1.8.4)
41
+ mini_portile2 (~> 2.3.0)
42
+ parallel (1.12.1)
43
+ parser (2.5.1.2)
44
+ ast (~> 2.4.0)
45
+ powerpack (0.1.2)
46
+ rails-dom-testing (2.0.3)
47
+ activesupport (>= 4.2.0)
48
+ nokogiri (>= 1.6)
49
+ rails-html-sanitizer (1.0.4)
50
+ loofah (~> 2.2, >= 2.2.2)
51
+ rainbow (3.0.0)
52
+ rake (12.3.1)
53
+ rspec (3.7.0)
54
+ rspec-core (~> 3.7.0)
55
+ rspec-expectations (~> 3.7.0)
56
+ rspec-mocks (~> 3.7.0)
57
+ rspec-core (3.7.1)
58
+ rspec-support (~> 3.7.0)
59
+ rspec-expectations (3.7.0)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.7.0)
62
+ rspec-html-matchers (0.9.1)
63
+ nokogiri (~> 1)
64
+ rspec (>= 3.0.0.a, < 4)
65
+ rspec-mocks (3.7.0)
66
+ diff-lcs (>= 1.2.0, < 2.0)
67
+ rspec-support (~> 3.7.0)
68
+ rspec-support (3.7.1)
69
+ rubocop (0.58.1)
70
+ jaro_winkler (~> 1.5.1)
71
+ parallel (~> 1.10)
72
+ parser (>= 2.5, != 2.5.1.1)
73
+ powerpack (~> 0.1)
74
+ rainbow (>= 2.2.2, < 4.0)
75
+ ruby-progressbar (~> 1.7)
76
+ unicode-display_width (~> 1.0, >= 1.0.1)
77
+ ruby-progressbar (1.9.0)
78
+ thread_safe (0.3.6)
79
+ tzinfo (1.2.5)
80
+ thread_safe (~> 0.1)
81
+ unicode-display_width (1.4.0)
82
+
83
+ PLATFORMS
84
+ ruby
85
+
86
+ DEPENDENCIES
87
+ bundler
88
+ faker
89
+ rake
90
+ rspec
91
+ rspec-html-matchers
92
+ rubocop
93
+ sorry-rails!
94
+
95
+ BUNDLED WITH
96
+ 1.16.2
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Robert Rawlins
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,107 @@
1
+ # Sorry™ - Rails
2
+
3
+ [![Build Status](https://travis-ci.org/sorry-app/sorry-rails.svg?branch=master)](https://travis-ci.org/sorry-app/sorry-rails)
4
+
5
+ > A Rails gem to add the [Sorry™ Website Plugin](https://github.com/sorry-app/status-bar) to your application. Easily display notices from your status page to your users, and register them as subscribers to receive updates when the particular parts of your application they use are experiencing issues.
6
+
7
+ ## Installation
8
+
9
+ #### Install the Gem
10
+
11
+ Add the gem to your Gemfile.
12
+
13
+ ```ruby
14
+ gem 'sorry-rails'
15
+ ```
16
+
17
+ Once this has been done you can run `bundle install` to install the gem into your bundle.
18
+
19
+ #### Create an Initializer
20
+
21
+ Create an initializer to configure your plugin, we'd suggest putting this in `/config/initializers/sorry-rails.rb`.
22
+
23
+ ```ruby
24
+ # Configure website plugin.
25
+ Sorry::Rails.configure do |config|
26
+ # Set the page identity.
27
+ config.page_id = 'xxxxxxxx'
28
+ end
29
+ ```
30
+
31
+ Place your own status page ID into the initializer, so the plugin knows where to pull your updates from.
32
+
33
+ #### Include the JavaScript
34
+
35
+ You can now use the helper method to include the appropriate JavaScript into your layouts and views.
36
+
37
+ ```erb
38
+ <!-- Plugin to install status notices. -->
39
+ <%= sorry_script_tag %>
40
+ ```
41
+
42
+ You'll most likely want to add this to `application.html.erb` so it displays on all pages.
43
+
44
+ ## Subscriber Data
45
+
46
+ By default the plugin plays nicely with [Devise](https://github.com/plataformatec/devise) by looking for a method called `current_user`, if this method returns an object with an `email` attribute they are passed along as a subscriber, so they'll appear in your subscribers list.
47
+
48
+ ### Custom current user method
49
+
50
+ If you don't use Devise, or it's default `current_user` method, you can customize the method name in your initializer.
51
+
52
+ ```ruby
53
+ config.current_user_method = :logged_in_user
54
+ ```
55
+
56
+ Pass a symbol which represents the method name, and we'll call that.
57
+
58
+ ### Subscribing to specific components (Established plan only)
59
+
60
+ Sometimes users don't utilize all of your application, and they'll only want updates about incidents which affect the parts they actually use. For example, if one of our customers uses our Mailgun integration, but Sendgrid is currently experiencing issues, they don't need to know.
61
+
62
+ You can pass us an array of component_ids that the subscriber is interested in.
63
+
64
+ ```ruby
65
+ # Method name example.
66
+ config.component_ids_method = :component_ids
67
+
68
+ # Proc based example.
69
+ config.component_ids_method = Proc.new { |user|
70
+ # Logic here to get array of IDs...
71
+ }
72
+ ```
73
+
74
+ As per the example, this can either be a method_name to be called on your current_user, or a Proc which is passed the current user, both should return an array of numeric component ids.
75
+
76
+ ## Contributing
77
+
78
+ In lieu of a formal style-guide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code.
79
+
80
+ Once you are happy that your contribution is ready for production please send us a pull request, at which point we'll review the code and merge it in.
81
+
82
+ ## Versioning
83
+
84
+ For transparency and insight into our release cycle, and for striving to maintain backward compatibility, This project will be maintained under the Semantic Versioning guidelines as much as possible.
85
+
86
+ Releases will be numbered with the following format:
87
+
88
+ `<major>.<minor>.<patch>`
89
+
90
+ And constructed with the following guidelines:
91
+
92
+ * Breaking backward compatibility bumps the major (and resets the minor and patch)
93
+ * New additions without breaking backward compatibility bumps the minor (and resets the patch)
94
+ * Bug fixes and misc changes bumps the patch
95
+
96
+ For more information on SemVer, please visit <http://semver.org/>.
97
+
98
+ ## Authors & Contributors
99
+
100
+ **Robert Rawlins**
101
+
102
+ + <http://twitter.com/sirrawlins>
103
+ + <https://github.com/SirRawlins>
104
+
105
+ ## Copyright
106
+
107
+ &copy; Copyright - See [LICENSE](LICENSE.txt) for details.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,38 @@
1
+ require 'sorry/rails/configuration'
2
+ require 'sorry/rails/script_tag_helper'
3
+ require 'sorry/rails/subscriber_serializer'
4
+ require 'sorry/rails/railtie' if defined?(::Rails::Railtie)
5
+ require 'sorry/rails/version'
6
+
7
+ module Sorry
8
+ #
9
+ # Mail rails plugin definition for
10
+ # the Sorry gem.
11
+ #
12
+ module Rails
13
+
14
+ # Define the JS plugin version to be used
15
+ # by the script tag generator.
16
+ PLUGIN_VERSION = '4.latest'.freeze
17
+
18
+ class << self
19
+
20
+ # Attr to store the configuration.
21
+ attr_accessor :configuration
22
+
23
+ # Allow configuration by block.
24
+ def configure
25
+ # Singleton the config instance.
26
+ self.configuration ||= Configuration.new
27
+
28
+ # Yield the config block.
29
+ yield(configuration)
30
+
31
+ # Return the config.
32
+ self.configuration
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ require 'hashie/dash'
2
+
3
+ module Sorry
4
+ module Rails
5
+ #
6
+ # Configuration class is a glorified hash
7
+ # for storing settings to be used by the plugin.
8
+ #
9
+ class Configuration < Hashie::Dash
10
+
11
+ # Define the properties in the config hash.
12
+ property :page_id
13
+ # Current user method, defaults to Devise compatible.
14
+ property :current_user_method, default: :current_user
15
+
16
+ # Property accessors for the subscriber.
17
+ property :email_method, default: :email
18
+ property :component_ids_method, default: :component_ids
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ module Sorry
2
+ module Rails
3
+ #
4
+ # Railtie loads the script tag helper into
5
+ # action view so we can inject the JS into
6
+ # the host applications templates.
7
+ #
8
+ class Railtie < ::Rails::Railtie
9
+
10
+ # On initialization.
11
+ initializer 'sorry-rails' do
12
+ # Action view helpers.
13
+ ActiveSupport.on_load :action_view do
14
+ # Include the script tag helper.
15
+ include Sorry::Rails::ScriptTagHelper
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ require 'active_support/all'
2
+ require 'action_view'
3
+
4
+ module Sorry
5
+ module Rails
6
+ #
7
+ # An ActionView helper which generates the JavaScript
8
+ # includes required for the plugin to work.
9
+ #
10
+ module ScriptTagHelper
11
+
12
+ # Base rails helpers we utilize.
13
+ include ActionView::Context
14
+ include ActionView::Helpers::AssetTagHelper
15
+ include ActionView::Helpers::JavaScriptHelper
16
+ #
17
+ # Generate the Sorry Website Plugin script
18
+ # tag to display status notices to the user
19
+ # and register them as a subscriber.
20
+ #
21
+ def sorry_script_tag(options = {})
22
+ # Merge configuration in options.
23
+ options.reverse_merge!(Sorry::Rails.configuration)
24
+
25
+ # Include the payload tag and the include
26
+ # tags for the plugin.
27
+ safe_join([sorry_script_payload_tag(options), sorry_script_include_tag(options)])
28
+ end
29
+
30
+ def sorry_script_include_tag(options)
31
+ # Build the JavaScript tag for the plugin include.
32
+ # Use the latest JS version defined in the plugin.
33
+ javascript_include_tag "https://code.sorryapp.com/status-bar/#{Sorry::Rails::PLUGIN_VERSION}/status-bar.min.js",
34
+ # Define the pages identity.
35
+ data: { for: options.fetch('page_id') },
36
+ # Load asynchronously.
37
+ async: true
38
+ end
39
+
40
+ def sorry_script_payload_tag(options)
41
+ # Get the method name
42
+ current_user_method = options.fetch('current_user_method')
43
+
44
+ # See if the current user is signed in, so we can
45
+ # include them as a subscriber.
46
+ if respond_to?(current_user_method) && send(current_user_method).present?
47
+ # Get the current user.
48
+ current_request_user = send(current_user_method)
49
+
50
+ # Serialize the user into a subscriber payload.
51
+ subscriber_payload = SubscriberSerializer.new(current_request_user).to_json
52
+
53
+ # We have a user method, let's include the JS payload
54
+ # object for them as a subscriber.
55
+ javascript_tag id: 'sorry-subscriber-data' do
56
+ # Include the subscriber payload on the window.
57
+ "window.SorryAPIOptions = { \"subscriber\": #{subscriber_payload} };".html_safe
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,93 @@
1
+ require 'json'
2
+
3
+ module Sorry
4
+ module Rails
5
+ #
6
+ # Serializer class takes the applications current_user
7
+ # and converts it into a safe JSON payload to be included
8
+ # in the plugin and sent to Sorry as a subscriber.
9
+ #
10
+ class SubscriberSerializer
11
+
12
+ # Define serializeable fields.
13
+ SERIALIZEABLE_ATTRIBUTES = %i[email component_ids].freeze
14
+
15
+ #
16
+ # Decorator which receives the current user
17
+ # model and safely converts them into JSON
18
+ # for adding to the payload.
19
+ #
20
+
21
+ def initialize(current_user)
22
+ # Set user instance.
23
+ @current_user = current_user
24
+ end
25
+
26
+ def to_json(serializeable_attributes = SERIALIZEABLE_ATTRIBUTES)
27
+ # Check the serializeable attributes are allowed.
28
+ serializeable_attributes!(serializeable_attributes)
29
+
30
+ # Start with an empty attributes hash
31
+ attributes = {}
32
+
33
+ # Loop over the collection or attributes
34
+ # we can serialize.
35
+ serializeable_attributes.each do |attribute|
36
+ # Add this attribute to the hash.
37
+ attributes[attribute] = attribute_value(attribute)
38
+ end
39
+
40
+ # Serialize the collection
41
+ # remove any attributes not serialized.
42
+ attributes.compact.to_json
43
+ end
44
+
45
+ #
46
+ # The value of the attribute can come
47
+ # from a proc, or from a custom field, or
48
+ # by looking for a direct attribute on the user.
49
+ #
50
+ def attribute_value(attribute)
51
+ # Get the configured method for the attribute.
52
+ attribute_method = Sorry::Rails.configuration.fetch("#{attribute}_method")
53
+
54
+ # See if the method is a proc.
55
+ if attribute_method.respond_to?(:call)
56
+ # It's a proc, call it with the model.
57
+ attribute_method.call(@current_user)
58
+ # See if the instance responds to it.
59
+ elsif @current_user.respond_to?(attribute_method)
60
+ # It's a method name, invoke
61
+ # the method on the model.
62
+ @current_user.public_send(attribute_method)
63
+ end
64
+ end
65
+
66
+ #
67
+ # Check attributes are serializeable and throw an exception
68
+ # if they're not included in SERIALIZEABLE_ATTRIBUTES
69
+ #
70
+ def serializeable_attributes!(serializeable_attributes)
71
+ # See if the attributes are serializeable.
72
+ unless serializeable_attributes?(serializeable_attributes)
73
+ # They're not, so throw an error.
74
+ raise UnserializableAttributeError, "The attributes (#{(serializeable_attributes - SERIALIZEABLE_ATTRIBUTES)}) are not included in the approved list."
75
+ end
76
+ end
77
+
78
+ #
79
+ # Determine if a collection of attribute names
80
+ # can be serialized or not.
81
+ #
82
+ def serializeable_attributes?(serializeable_attributes)
83
+ # Check that all appear in SERIALIZEABLE_ATTRIBUTES
84
+ (serializeable_attributes - SERIALIZEABLE_ATTRIBUTES).empty?
85
+ end
86
+
87
+ # Custom error for when someone asks to serialize an
88
+ # attribute not listed in SERIALIZEABLE_ATTRIBUTES.
89
+ class UnserializableAttributeError < StandardError; end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,8 @@
1
+ module Sorry
2
+ module Rails
3
+
4
+ # Define version number on release.
5
+ VERSION = '0.1.2'.freeze
6
+
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'sorry/rails/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sorry-rails'
7
+ spec.version = Sorry::Rails::VERSION
8
+ spec.authors = ['Robert Rawlins']
9
+ spec.email = ['robert@sorryapp.com']
10
+
11
+ spec.summary = 'Add the Sorry™ website plugin to your Rails application.'
12
+ spec.description = 'Display status updates from your Sorry™ status page to your users, and affectively customize which notices each user should see.'
13
+ spec.homepage = 'https://github.com/sorry-app/sorry-rails'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
+
18
+ spec.add_development_dependency 'bundler'
19
+ spec.add_development_dependency 'faker'
20
+ spec.add_development_dependency 'rake'
21
+ spec.add_development_dependency 'rspec'
22
+ spec.add_development_dependency 'rspec-html-matchers'
23
+ spec.add_development_dependency 'rubocop'
24
+
25
+ spec.add_dependency 'actionview'
26
+ spec.add_dependency 'activesupport'
27
+ spec.add_dependency 'hashie', '~> 2.0'
28
+ end
@@ -0,0 +1,16 @@
1
+ RSpec.describe Sorry::Rails::Configuration do
2
+
3
+ # Get an instance for testing.
4
+ subject { described_class.new }
5
+
6
+ describe '#current_user_method' do
7
+ # Get the current user method.
8
+ subject { super().current_user_method }
9
+
10
+ context 'by default' do
11
+ # Check the Devise focussed default.
12
+ it { is_expected.to eq(:current_user) }
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,72 @@
1
+ RSpec.describe Sorry::Rails::ScriptTagHelper, type: :helper do
2
+
3
+ # Include the helper methods for testing.
4
+ include described_class
5
+
6
+ # Mock a page identity to be used.
7
+ let(:page_id) { Faker::Lorem.characters(8) }
8
+
9
+ describe '#sorry_script_tag' do
10
+ # Get the resulting tag for testing.
11
+ subject { sorry_script_tag('page_id' => page_id) }
12
+
13
+ # Expect string return.
14
+ it { is_expected.to be_a(String) }
15
+ it { is_expected.to be_html_safe }
16
+ it {
17
+ # Expect an asynchronous JavaScript tag.
18
+ is_expected.to have_tag('script[async]', with: {
19
+ # Pointing at the latest version.
20
+ src: "https://code.sorryapp.com/status-bar/#{Sorry::Rails::PLUGIN_VERSION}/status-bar.min.js",
21
+ # With the configured page identity.
22
+ 'data-for': page_id
23
+ })
24
+ }
25
+
26
+ describe 'subscriber_payload' do
27
+ # The subscribe payload tag id.
28
+ let(:subscriber_payload_tag) { 'script[id="sorry-subscriber-data"]' }
29
+
30
+ context 'without current_user method' do
31
+ # IT should not include the payload
32
+ it { is_expected.to_not have_tag(subscriber_payload_tag) }
33
+ end
34
+
35
+ context 'with current_user method' do
36
+ # Make the configured user method available, and
37
+ # have it return the mock user.
38
+ before(:each) do
39
+ # Mock the method onto the test class.
40
+ allow(self).to receive(Sorry::Rails.configuration.current_user_method).and_return(mock_user)
41
+ end
42
+
43
+ context 'and no user' do
44
+ # Mock no user.
45
+ let(:mock_user) { nil }
46
+
47
+ # IT should not include the payload
48
+ it { is_expected.to_not have_tag(subscriber_payload_tag) }
49
+ end
50
+
51
+ context 'and user is signed in' do
52
+ # Mock a user object with an email address
53
+ # we can pretend is signed in.
54
+ let(:mock_user) { double('User', email: Faker::Internet.email) }
55
+
56
+ # Expect the subscriber payload
57
+ it 'contains the expect payload tag' do
58
+ # Mock the JSON payload for the user.
59
+ subscriber_payload = Sorry::Rails::SubscriberSerializer.new(mock_user).to_json
60
+
61
+ # Check for the script tag.
62
+ is_expected.to have_tag(subscriber_payload_tag) do
63
+ # Check the serializer JSON payload.
64
+ with_text(/window.SorryAPIOptions = { \"subscriber\": #{subscriber_payload} };/)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,89 @@
1
+ RSpec.describe Sorry::Rails::SubscriberSerializer do
2
+
3
+ # Mock a subscriber / user to serialize
4
+ # during the tests.
5
+ let(:current_user) { double('User') }
6
+
7
+ describe '#to_json' do
8
+ # Loop over the attributes to check each.
9
+ described_class::SERIALIZEABLE_ATTRIBUTES.each do |attribute|
10
+ # Context for this attribute.
11
+ context "when serializing #{attribute}" do
12
+ # Get the JSON hash for testing, only include
13
+ # a single attribute at a time, easier mocking for tests.
14
+ subject { described_class.new(current_user).to_json([attribute]) }
15
+
16
+ context 'the resulting value' do
17
+ # Get the payload result for testing.
18
+ subject { JSON.parse(super()).fetch(attribute.to_s) }
19
+
20
+ context 'when customized' do
21
+ # Mock the custom method result.
22
+ let(:custom_method_result) { Faker::Lorem.sentence }
23
+
24
+ context 'when a customer proc' do
25
+ # Stage the user/config for the method.
26
+ before(:each) do
27
+ # Allow the user to receive the method.
28
+ allow(current_user).to receive(:value_through_proc).and_return(custom_method_result)
29
+
30
+ # Mock the method as a Proc.
31
+ Sorry::Rails.configuration.send(:"#{attribute}_method=", proc { |user| user.value_through_proc })
32
+ end
33
+
34
+ # Expect the custom result.
35
+ it { is_expected.to eq(custom_method_result) }
36
+ end
37
+
38
+ context 'when a custom method name' do
39
+ # Mock a custom method name.
40
+ let(:custom_method_name) { Faker::Lorem.word.to_sym }
41
+
42
+ # Stage the user/config for the method.
43
+ before(:each) do
44
+ # Allow the user to receive the method.
45
+ allow(current_user).to receive(custom_method_name).and_return(custom_method_result)
46
+
47
+ # Add the method to the config.
48
+ Sorry::Rails.configuration.send(:"#{attribute}_method=", custom_method_name)
49
+ end
50
+
51
+ # Expect the custom result.
52
+ it { is_expected.to eq(custom_method_result) }
53
+ end
54
+ end
55
+
56
+ context 'when the default method' do
57
+ # Mock the attribute method on the model.
58
+ before(:each) { allow(current_user).to receive(attribute).and_return(Faker::Lorem.sentence) }
59
+
60
+ # Is the users own attribute.
61
+ it { is_expected.to eq(current_user.send(attribute)) }
62
+ end
63
+
64
+ context 'when no matching method on model' do
65
+ # Remove the method from the model.
66
+ before(:each) { allow(current_user).to receive(:respond_to?).with(attribute).and_return(false) }
67
+
68
+ it 'does not include the attribute' do
69
+ # Expect no matching key in the hash.
70
+ expect { subject }.to raise_error(KeyError)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ context 'when passed non-serializeable attribute name' do
78
+ # Ask for JSON with a random attribute name not
79
+ # found in the SERIALIZEABLE_ATTRIBUTES constant.
80
+ subject { described_class.new(current_user).to_json([Faker::Lorem.word]) }
81
+
82
+ it 'raises a custom error' do
83
+ # Expect an error to be thrown.
84
+ expect { subject }.to raise_error(Sorry::Rails::SubscriberSerializer::UnserializableAttributeError)
85
+ end
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,62 @@
1
+ RSpec.describe Sorry::Rails do
2
+
3
+ describe '#configure' do
4
+ # Mock some detailed to pass to the config.
5
+ let(:page_id) { Faker::Lorem.characters(8) }
6
+
7
+ context 'when passed a block' do
8
+ subject do
9
+ # Invoke the configure with
10
+ # a block, setting a mock Page ID.
11
+ described_class.configure do |config|
12
+ # Set the mock page identity.
13
+ config.page_id = page_id
14
+ end
15
+ end
16
+
17
+ # Check a configuration instance records.
18
+ it { is_expected.to be_a(described_class::Configuration) }
19
+
20
+ describe 'the configured page_id' do
21
+ # Get the page if for testing.
22
+ subject { super().page_id }
23
+
24
+ # Is the one passed in.
25
+ it { is_expected.to eq(page_id) }
26
+ end
27
+ end
28
+ end
29
+
30
+ describe '#configuration' do
31
+ # Get the configuration for testing.
32
+ subject { described_class.configuration }
33
+
34
+ context 'when previously configured' do
35
+ # Mock the configuration.
36
+ let(:configuration) { described_class::Configuration.new }
37
+
38
+ # Put the configuration in place.
39
+ before(:each) { described_class.configuration = configuration }
40
+
41
+ # Returns a config class.
42
+ it { is_expected.to be(configuration) }
43
+ end
44
+
45
+ context 'when not configured' do
46
+ # Put the configuration in place.
47
+ before(:each) { described_class.configuration = nil }
48
+
49
+ # It has not config.
50
+ it { is_expected.to be_nil }
51
+ end
52
+ end
53
+
54
+ describe 'version number' do
55
+ # Get version for testing.
56
+ subject { described_class::VERSION }
57
+
58
+ # Should be present.
59
+ it { is_expected.not_to be_nil }
60
+ end
61
+
62
+ end
@@ -0,0 +1,32 @@
1
+ require 'bundler/setup'
2
+ require 'faker'
3
+ require 'sorry/rails'
4
+ require 'rspec-html-matchers'
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = '.rspec_status'
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ # Use more modern syntax.
15
+ c.syntax = :expect
16
+ end
17
+
18
+ # Reset config singleton after each test.
19
+ config.around(:each) do |example|
20
+ # Create a default plugin config.
21
+ Sorry::Rails.configuration ||= Sorry::Rails::Configuration.new
22
+
23
+ # Run the examples.
24
+ example.run
25
+
26
+ # Remove the config.
27
+ Sorry::Rails.configuration = nil
28
+ end
29
+
30
+ # Include have_tag matchers.
31
+ config.include RSpecHtmlMatchers
32
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorry-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Rawlins
@@ -143,7 +143,28 @@ email:
143
143
  executables: []
144
144
  extensions: []
145
145
  extra_rdoc_files: []
146
- files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".rspec"
149
+ - ".rubocop.yml"
150
+ - ".travis.yml"
151
+ - Gemfile
152
+ - Gemfile.lock
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - lib/sorry/rails.rb
157
+ - lib/sorry/rails/configuration.rb
158
+ - lib/sorry/rails/railtie.rb
159
+ - lib/sorry/rails/script_tag_helper.rb
160
+ - lib/sorry/rails/subscriber_serializer.rb
161
+ - lib/sorry/rails/version.rb
162
+ - sorry-rails.gemspec
163
+ - spec/sorry/rails/configuration_spec.rb
164
+ - spec/sorry/rails/script_tag_helper_spec.rb
165
+ - spec/sorry/rails/subscriber_serializer_spec.rb
166
+ - spec/sorry/rails_spec.rb
167
+ - spec/spec_helper.rb
147
168
  homepage: https://github.com/sorry-app/sorry-rails
148
169
  licenses:
149
170
  - MIT