auto_previews 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7e58cc642265b751c8bf94fe3291e36427077120199649b622bd2525781a154c
4
+ data.tar.gz: 7fe02d77b9c2ac02647c47bb1322f9f3dbae1644ee2068b004d55a2d7ccdfd4b
5
+ SHA512:
6
+ metadata.gz: 5b3c42fd3f5e1e486f8ef94508777507d73a610d8bd71c1138eeb8365f87879a548d07ff7bc7ce560d65a386c385652692a65bc34088ebbfe173fd28ce7e441d
7
+ data.tar.gz: 24c1bc6173bb4b0393414f5ddfd6c1d4eb2956225f7afdb8271516b44aae1fc10efeab597316c3740c5fd8bc2e62da6c4aa930337cd2f02ec3414ca4de3f99f5
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Josh Brody
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.
@@ -0,0 +1,111 @@
1
+ # AutoPreviews
2
+
3
+ I got tired of writing `ActionMailer::Preview` classes. So I let Ruby write it for me.
4
+
5
+ ## Usage
6
+
7
+ In your mailer class, define some options:
8
+
9
+ ```ruby
10
+ class PostMailer < ApplicationMailer
11
+ previews_for model: 'Post', # otherwise automatically infered based on class.name.delete_suffix('Mailer')
12
+ params: { post_id: :id },
13
+ only: [:created]
14
+
15
+ previews_for model: 'Post',
16
+ params: { post_id: :id },
17
+ only: [:deleted],
18
+ scope: :with_deleted,
19
+ using: :arguments
20
+
21
+ before_action only: [:created] do
22
+ @post = Post.find_by(id: params[:post_id])
23
+ end
24
+
25
+ def created
26
+ mail(to: "joshmn@example.com", subject: "Nice post #{@post.id}")
27
+ end
28
+
29
+ def deleted(post_id)
30
+ @post = Post.find_by(id: post_id)
31
+ mail(to: "joshmn@example.com", subject: "Deleted post #{@post.id}")
32
+ end
33
+ end
34
+ ```
35
+
36
+ In your previewer class, just call `auto_preview!`
37
+
38
+ ```ruby
39
+ class PostMailerPreview < ActionMailer::Preview
40
+ auto_preview!
41
+ end
42
+ ```
43
+
44
+ `auto_preview!` will do some metaprogramming to create your mailer previews, like so:
45
+
46
+ ```ruby
47
+ post = Post.first
48
+ params_to_send_to_mailer = {}
49
+ params_given = { post_id: :id }
50
+ params_given.each do |mailer_key, model_method|
51
+ params_to_send_to_mailer[mailer_key] = post.public_send(model_method)
52
+ end
53
+ PostMailer.with(params_to_send_to_mailer).created # or `*params_to_send_to_mailer.values` if `using: :arguments`
54
+ ```
55
+
56
+ ## Installation
57
+
58
+ 1. Add this line to your application's Gemfile:
59
+
60
+ ```ruby
61
+ gem 'auto_previews'
62
+ ```
63
+
64
+ 2. And then execute:
65
+ ```bash
66
+ $ bundle
67
+ ```
68
+
69
+ 3. Restart your Rails server
70
+
71
+ 4. Implement
72
+
73
+ 5. Enjoy!
74
+
75
+ ## Options
76
+
77
+ By default, the `previews_for` will define mailer preview methods for `class.instance_methods(false)`.
78
+
79
+ * `model`: the model you want to use for the record lookup; defaults to `self.class.name.delete_suffix('Mailer')`; if
80
+ `false` is passed, no model will be used
81
+ * `params`: a hash of `mailer_method_name: :model_method_name`; used to map values to the mailer from the model
82
+ * `using`: the type of mailer to use; defaults to using `ActionMailer::Parameterized`
83
+ * `only`: the methods to only use the given `previews_for` on; defaults to `[]`
84
+ * `except`: the methods to not use the given `previews_for` on; defaults to `[]`
85
+ * `scope`: scope to use on the model; defaults to `:all`
86
+
87
+ ## Usage without a model
88
+
89
+ Just pass `model: false` and define some sort of values to pass in the `params`:
90
+
91
+ Passing a proc will `call`; passing a symbol will call the given method on the mailer preview class if it is defined, otherwise it will be sent to your mailer preview as the symbol.
92
+
93
+ ```ruby
94
+ class OneOffMailer < ApplicationMailer
95
+ previews_for model: false,
96
+ params: {
97
+ subject: -> :random_subject,
98
+ body: -> { FFaker::CheesyLingo.paragraph },
99
+ },
100
+ end
101
+ ```
102
+
103
+ ## Roadmap
104
+
105
+ * More options
106
+ * Better extensibility
107
+ * Better record lookup
108
+ * Better serialization of mailer params
109
+
110
+ ## License
111
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'AutoPreviews'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
18
+
19
+ require 'rake/testtask'
20
+
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.libs << 'test'
23
+ t.pattern = 'test/**/*_test.rb'
24
+ t.verbose = false
25
+ end
26
+
27
+ task default: :test
@@ -0,0 +1,5 @@
1
+ require 'auto_previews/preview_extensions'
2
+ require 'auto_previews/action_mailer_extensions'
3
+ require "auto_previews/railtie"
4
+
5
+ module AutoPreviews; end
@@ -0,0 +1,35 @@
1
+ module AutoPreviews
2
+ module ActionMailerExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ # use an array so we can use only/except
11
+ def previews_for(options = {})
12
+ autopreview_configs << _normalized_previews_for_options(options)
13
+ end
14
+
15
+ def autopreview_configs
16
+ @_autopreview_configs ||= []
17
+ end
18
+
19
+ private
20
+
21
+ def _normalized_previews_for_options(options)
22
+ unless options[:model] === false
23
+ options[:model] ||= self.class.name.delete_suffix('Mailer')
24
+ if options[:model].is_a?(Class)
25
+ options[:model] = options[:model].to_s
26
+ end
27
+ options[:scope] ||= :all
28
+ end
29
+ options[:using] ||= :parameters
30
+ options
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,83 @@
1
+ module AutoPreviews
2
+ module PreviewExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do #
6
+ extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def auto_preview!(klass = nil)
11
+ mailer_class = (klass || self.name.delete_suffix("Preview")).constantize
12
+ mailer_class.autopreview_configs.each do |autopreview_config|
13
+ methods_to_define = if autopreview_config[:except]
14
+ mailer_class.instance_methods(false) - Array(autopreview_config[:except])
15
+ elsif autopreview_config[:only]
16
+ Array(autopreview_config[:only])
17
+ else
18
+ mailer_class.instance_methods(false)
19
+ end
20
+ methods_to_define.each do |m|
21
+ model = setup_model(autopreview_config[:model])
22
+ scoped_collection = setup_scope(model, autopreview_config)
23
+ finder = record_finder(scoped_collection, autopreview_config)
24
+ record_proc, preview_params = finder[0], finder[1]
25
+ define_method(m) do
26
+ mailer_params = {}
27
+ record = record_proc.call
28
+ if record.nil?
29
+ raise ActiveRecord::RecordNotFound, "Cannot find a record. Should be a type of `#{model}`. Create one?"
30
+ end
31
+ preview_params.each do |k,v|
32
+ mailer_params[k] = record.public_send(v)
33
+ end
34
+ if autopreview_config[:using] == :arguments
35
+ mailer_class.public_send(m, *mailer_params.values)
36
+ else
37
+ mailer_class.with(mailer_params).public_send(m)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def setup_model(model_class)
47
+ return false if model_class === false
48
+ model = model_class.safe_constantize || model_class.to_s.delete_suffix('MailerPreview').safe_constantize
49
+ if model.nil?
50
+ raise ArgumentError, "unable to infer model from `#{model_class}`."
51
+ end
52
+ model
53
+ end
54
+
55
+ def setup_scope(model, config)
56
+ return model if config[:model] === false
57
+ scope = config[:scope]
58
+ scoped_collection = model
59
+ if scope.is_a?(Proc)
60
+ scoped_collection = scoped_collection.call(scope)
61
+ elsif scope.is_a?(Symbol)
62
+ scoped_collection = scoped_collection.send(scope)
63
+ else
64
+ raise ArgumentError, "invalid scope for #{model} `#{scope.inspect}`"
65
+ end
66
+ scoped_collection
67
+ end
68
+
69
+ # I hate this. So hacky.
70
+ def record_finder(collection, config)
71
+ if config[:model] === false
72
+ struct = OpenStruct.new
73
+ config[:params].each do |k,v|
74
+ struct[k] = v
75
+ config[:params][k] = k
76
+ end
77
+ return [-> { struct }, config[:params]]
78
+ end
79
+ [-> { collection.first }, config[:params]]
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,8 @@
1
+ module AutoPreviews
2
+ class Railtie < ::Rails::Railtie
3
+ ActiveSupport.on_load(:action_mailer) do
4
+ include ::AutoPreviews::ActionMailerExtensions
5
+ ::ActionMailer::Preview.include AutoPreviews::PreviewExtensions
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module AutoPreviews
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auto_previews
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh Brody
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.3
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '5.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 6.0.3
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: sqlite3
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Automatically create mailer previews for your mailers.
48
+ email:
49
+ - git@josh.mn
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - MIT-LICENSE
55
+ - README.md
56
+ - Rakefile
57
+ - lib/auto_previews.rb
58
+ - lib/auto_previews/action_mailer_extensions.rb
59
+ - lib/auto_previews/preview_extensions.rb
60
+ - lib/auto_previews/railtie.rb
61
+ - lib/auto_previews/version.rb
62
+ homepage: https://github.com/joshmn/auto_previews
63
+ licenses:
64
+ - MIT
65
+ metadata:
66
+ allowed_push_host: https://rubygems.org
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.1.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Automatically create mailer previews for your mailers.
86
+ test_files: []