nisetegami 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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.md ADDED
@@ -0,0 +1,5 @@
1
+ ## Nisetegami
2
+
3
+
4
+
5
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Nisetegami'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ Bundler::GemHelper.install_tasks
25
+
26
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
27
+ load 'rails/tasks/engine.rake'
28
+
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ desc 'Default: Run all specs.'
35
+ task default: :spec
@@ -0,0 +1,157 @@
1
+ class Nisetegami::Template < ActiveRecord::Base
2
+
3
+ self.table_name = :nisetegami_templates
4
+
5
+ ## constants
6
+
7
+ CONTENT = [:subject, :body_html, :body_text]
8
+ HEADERS = [:cc, :bcc, :reply_to, :from]
9
+
10
+ ## scopes
11
+
12
+ scope :by_mailer, ->(mailer){ where(mailer: mailer.respond_to?(:name) ? mailer.name : mailer) }
13
+ scope :by_action, ->(action){ where(action: action) }
14
+ scope :by_layout, ->(layout){ where(layout: layout) }
15
+ scope :enabled, where(enabled: true)
16
+ scope :disabled, where(enabled: false)
17
+ scope :html, where(only_text: false)
18
+ scope :text, where(only_text: true)
19
+
20
+ ## validations
21
+ email_re = '[-a-z0-9_+\.]+@([-a-z0-9]+\.)+[a-z0-9]{2,}'
22
+ address_re = "(?:[^<@]+\\s+<#{email_re}>|#{email_re})"
23
+ addresses_re = /^#{address_re}(?:\s*,\s*#{address_re})*$/i
24
+ validates_format_of :from, :reply_to, :cc, :bcc, with: addresses_re, allow_blank: true
25
+ validate :subject, :body_text, :layout_text, :name, presence: true
26
+ validate :body_html, :layout_html, presence: true, unless: :only_text?
27
+ validate :check_template_syntax
28
+ validate :check_mailer
29
+
30
+ ## class-methods
31
+
32
+ # Accepts an instance of the ActionMailer::Base subclass
33
+ # and attempts to find associated template using
34
+ # name and action_name of the mailer.
35
+ def self.lookup(mailer_instance)
36
+ relation.where(mailer: mailer_instance.class.name, action: mailer_instance.action_name).first
37
+ end
38
+
39
+ public
40
+
41
+ def layout_html_path
42
+ layout_html && File.join(Nisetegami.layouts_path, layout_html)
43
+ end
44
+
45
+ def layout_text_path
46
+ layout_text && File.join(Nisetegami.layouts_path, layout_text)
47
+ end
48
+
49
+ # Returns a mapping for +self+, as a Hash.
50
+ def mapping
51
+ @_mapping ||= ::Nisetegami.mapping.lookup(mailer, action)
52
+ end
53
+
54
+ # Returns a list of variables for +self+,
55
+ # using a Nisetegami::Mapping definitions.
56
+ def variable_names
57
+ @_variable_names ||= mapping.keys
58
+ end
59
+
60
+ def variable_mapping
61
+ @_variable_mapping ||= begin
62
+ mapping.each_with_object([]) do |(variable, thing), array|
63
+ # @todo: store variable_mapping in mapping instead of classes [?]
64
+ meths = Nisetegami::Utils.liquid_methods_for(Nisetegami.cast[thing])
65
+ array << (meths.blank? ? variable.to_sym : { variable.to_sym => meths })
66
+ end
67
+ end
68
+ end
69
+
70
+ def mailer
71
+ @_mailer ||= self[:mailer].constantize
72
+ rescue NameError
73
+ end
74
+
75
+ CONTENT.each do |attribute|
76
+ define_method "#{attribute}=" do |raw|
77
+ self[attribute] = raw.blank? ? nil : raw
78
+ instance_variable_set("@#{attribute}_template", nil)
79
+ end
80
+
81
+ define_method "render_#{attribute}" do |variables|
82
+ return nil unless self[attribute]
83
+ # do not parse invalid templates
84
+ if instance_variable_get("@#{attribute}_template").nil?
85
+ instance_variable_set("@#{attribute}_template", try_parse_template(attribute))
86
+ end
87
+ instance_variable_get("@#{attribute}_template") \
88
+ .try(:render, variables.stringify_keys.select { |k, v| k.in?(variable_names) })
89
+ end
90
+ end
91
+
92
+ def headers(variables = {})
93
+ options = { subject: render_subject(variables) }
94
+ options[:css] = associated_stylesheets unless only_text?
95
+ HEADERS.each { |header| options[header] = self[header] unless self[header].blank? }
96
+ options
97
+ end
98
+
99
+ def message(recipient, variables)
100
+ return nil unless valid?
101
+ mailer.testing(action, recipient, variables)
102
+ end
103
+
104
+ private
105
+
106
+ def associated_stylesheets
107
+ @@asset_provider ||= Nisetegami::AssetProvider.new(Roadie.current_provider.prefix)
108
+ stylesheets = [:default]
109
+ stylesheets << layout_html unless layout_html.blank?
110
+ stylesheets.map! { |s| File.join('nisetegami', s.to_s) }
111
+ stylesheets.select { |s| @@asset_provider.exists?(s) }
112
+ end
113
+
114
+ def check_mailer
115
+ errors.add(:mailer, :undefined) if !mailer || !mailer.ancestors.include?(ActionMailer::Base)
116
+ errors.add(:action, :undefined) if mailer && !mailer.action_methods.include?(action.to_s)
117
+ end
118
+
119
+ def check_template_syntax
120
+ CONTENT.each { |attribute| try_parse_template(attribute) }
121
+ end
122
+
123
+ def try_parse_template(attribute)
124
+ Liquid::Template.parse(self[attribute])
125
+ rescue Liquid::SyntaxError => error
126
+ errors.add(attribute, :liquid_syntax_error, message: error.message)
127
+ false
128
+ end
129
+
130
+ end
131
+
132
+ # == Schema Information
133
+ #
134
+ # Table name: nisetegami_templates
135
+ #
136
+ # id :integer not null, primary key
137
+ # mailer :string(255)
138
+ # action :string(255)
139
+ # name :string(255)
140
+ # from :string(255)
141
+ # cc :string(255)
142
+ # bcc :string(255)
143
+ # reply_to :string(255)
144
+ # subject :text
145
+ # body_text :text
146
+ # body_html :text
147
+ # layout_text :string(255)
148
+ # layout_html :string(255)
149
+ # enabled :boolean default(FALSE), not null
150
+ # created_at :datetime not null
151
+ # updated_at :datetime not null
152
+ #
153
+ # Indexes
154
+ #
155
+ # index_nisetegami_templates_on_mailer_and_action (mailer,action) UNIQUE
156
+ #
157
+
@@ -0,0 +1,35 @@
1
+ class CreateNisetegamiTemplates < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :nisetegami_templates do |t|
4
+
5
+ ## mapping
6
+ t.string :mailer # EG: "TestMailer"
7
+ t.string :action # EG: "simple"
8
+ t.string :name # results in "TestMailer#simple"
9
+
10
+ ## headers
11
+ t.string :from
12
+ t.string :cc
13
+ t.string :bcc
14
+ t.string :reply_to
15
+
16
+ ## content
17
+ t.text :subject
18
+ t.text :body_text
19
+ t.text :body_html
20
+ t.text :layout_text
21
+ t.text :layout_html
22
+
23
+ ## controls
24
+ t.boolean :enabled, null: false, default: false
25
+ t.boolean :only_text, null: false, default: true
26
+
27
+ t.timestamps
28
+ end
29
+ add_index :nisetegami_templates, [:mailer, :action], unique: true
30
+ end
31
+
32
+ def self.down
33
+ drop_table :nisetegami_templates
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class Nisetegami::TemplatesGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
8
+
9
+ def self.next_migration_number(dirname)
10
+ if ActiveRecord::Base.timestamped_migrations
11
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
12
+ else
13
+ "%.3d" % (current_migration_number(dirname) + 1)
14
+ end
15
+ end
16
+
17
+ def create_migrations
18
+ Dir[File.join(self.class.source_root, 'migrations/*.rb')].sort.each do |template|
19
+ basename = File.basename(template).gsub(/^\d+_/, '')
20
+ if self.class.migration_exists?(File.join(Rails.root, 'db/migrate'), basename.sub(/\.rb$/, '')).blank?
21
+ migration_template template, "db/migrate/#{basename}"
22
+ sleep 1
23
+ end
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,77 @@
1
+ module Nisetegami
2
+ module ActionMailerExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ append_view_path ARTemplateResolver.instance
7
+ append_view_path "#{Rails.root}/app/views/nisetegami"
8
+ alias_method_chain :collect_responses_and_parts_order, :required_parts_order
9
+ alias_method_chain :mail, :template
10
+ alias_method_chain :render, :layout
11
+ end
12
+
13
+ module ClassMethods
14
+ def testing(action, recipient, variables)
15
+ new.testing do |instance|
16
+ instance.action_name = action.to_s
17
+ variables.each { |k, v| instance.instance_variable_set("@#{k}", v) }
18
+ instance.mail to: recipient
19
+ end
20
+ end
21
+ end
22
+
23
+ def render_with_layout(*args, &block)
24
+ options = args.first
25
+ if !options[:layout] && @_ar_template
26
+ format = options[:template].identifier.split('.').last
27
+ options[:layout] = @_ar_template.send("layout_#{format}")
28
+ end
29
+ render_without_layout(*args, &block)
30
+ end
31
+
32
+ def mail_with_template(headers = {}, &block)
33
+ # maybe there is better way? - do not want to do query it (despite cache is used) for second time
34
+ @_ar_template = Template.by_mailer(self.class).by_action(action_name).first
35
+ if @_ar_template
36
+ self.action_name ||= @_ar_template.action.to_s
37
+ # think about this ugly shit
38
+ vars = instance_variables.inject({}) do |hsh, var|
39
+ unless var =~ /@_/
40
+ template_var = instance_variable_get(var)
41
+ template_var = begin
42
+ instance_variable_set(var, "#{template_var.class}Decorator".constantize.decorate(template_var))
43
+ rescue NameError
44
+ template_var
45
+ end
46
+ hsh[var[1..-1].to_sym] = template_var
47
+ end
48
+ hsh
49
+ end
50
+ headers.reverse_merge!(@_ar_template.headers(vars))
51
+ end
52
+ mail_without_template(headers, &block).tap do |m|
53
+ m.perform_deliveries = testing? || !@_ar_template || @_ar_template.enabled
54
+ m.body = nil unless m.perform_deliveries # better to remove corresponding specs??
55
+ end
56
+ end
57
+
58
+ def testing(&block)
59
+ @_testing_was, @_testing = @_testing, true
60
+ yield self
61
+ ensure
62
+ @_testing = @_testing_was
63
+ end
64
+
65
+ protected
66
+
67
+ def testing?
68
+ !!@_testing
69
+ end
70
+
71
+ def collect_responses_and_parts_order_with_required_parts_order(headers)
72
+ responses, parts_order = collect_responses_and_parts_order_without_required_parts_order(headers)
73
+ [responses, parts_order || responses.map { |r| r[:content_type] }]
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,24 @@
1
+ require 'singleton'
2
+
3
+ class Nisetegami::ARTemplateResolver < ActionView::Resolver
4
+
5
+ include Singleton
6
+
7
+ def find_templates(name, prefix, partial, details)
8
+ Nisetegami::Template.by_mailer(prefix.classify).by_action(name).map do |record|
9
+ formats = [:text]
10
+ formats.unshift(:html) unless record.only_text?
11
+ formats.map do |format|
12
+ source = record.send("body_#{format}")
13
+ identifier = "Nisetegami::Template.#{record.id}.#{format}"
14
+ handler = ActionView::Template.registered_template_handler(:liquid)
15
+ details = {
16
+ format: Mime[format],
17
+ virtual_path: "#{record.mailer.to_s.underscore}/#{record.action}",
18
+ updated_at: record.updated_at
19
+ }
20
+ ActionView::Template.new(source, identifier, handler, details)
21
+ end
22
+ end.flatten
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module Nisetegami
2
+ class AssetProvider < Roadie::AssetPipelineProvider
3
+
4
+ def exists?(name)
5
+ !asset_file(name).nil?
6
+ end
7
+
8
+ def asset_file(name)
9
+ basename = remove_prefix(name)
10
+ assets[basename]
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ require 'nisetegami'
2
+
3
+ module Nisetegami
4
+ class Engine < Rails::Engine
5
+ isolate_namespace Nisetegami
6
+
7
+ initializer 'nisetegami.action_mailer' do |app|
8
+ ActiveSupport.on_load :action_mailer do
9
+ include Nisetegami::ActionMailerExtensions
10
+ end
11
+ end
12
+
13
+ config.before_initialize do
14
+ Nisetegami.class_variable_set(:@@layouts_path, Rails.root.join('app/views/nisetegami/layouts').to_s)
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module Nisetegami
2
+ module Exceptions
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ class UnknownActionError < Error
8
+ def initialize(mailer, action)
9
+ @action = "#{mailer}##{action}"
10
+ end
11
+ def message
12
+ "Action #{@action} does not exist. You should define it first."
13
+ end
14
+ end
15
+
16
+ class MissingTemplateError < Error
17
+ def initialize(mailer_instance)
18
+ @action = "#{mailer_instance.class.name}##{mailer_instance.action_name}"
19
+ end
20
+ def message
21
+ "Template for #{@action} not found. " \
22
+ "You should define it manually or use Nisetegami.populate!"
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ class ActionView::Template::Handlers::Liquid
2
+
3
+ def self.call(template)
4
+ "ActionView::Template::Handlers::Liquid.new(self).render(#{template.source.inspect}, local_assigns)"
5
+ end
6
+
7
+ def initialize(view)
8
+ @view = view
9
+ end
10
+
11
+ def render(template, local_assigns = {})
12
+ assigns = @view.assigns
13
+ assigns["content_for_layout"] = @view.content_for(:layout) if @view.content_for?(:layout)
14
+ assigns.merge!(local_assigns.stringify_keys)
15
+
16
+ controller = @view.controller
17
+ filters = if controller.respond_to?(:liquid_filters, true)
18
+ controller.send(:liquid_filters)
19
+ elsif controller.respond_to?(:master_helper_module)
20
+ [controller.master_helper_module]
21
+ else
22
+ [controller._helpers]
23
+ end
24
+
25
+ liquid = Liquid::Template.parse(template)
26
+ liquid.render(assigns, filters: filters, registers: { action_view: @view, controller: @view.controller })
27
+ end
28
+
29
+ def compilable?
30
+ false
31
+ end
32
+ end
33
+
34
+ ActionView::Template.register_template_handler :liquid, ActionView::Template::Handlers::Liquid
@@ -0,0 +1,73 @@
1
+ module Nisetegami
2
+ class Mapping
3
+ attr_reader :mailers
4
+
5
+ SEPARATOR = "#"
6
+
7
+ def initialize
8
+ @mailers = Set.new
9
+ @mapping = {}
10
+ end
11
+
12
+ def register(mailer, action, *locals)
13
+ mailer = mailer.to_s.classify
14
+ unless action_exists?(mailer, action)
15
+ raise Exceptions::UnknownActionError.new(mailer, action)
16
+ end
17
+ @mapping["#{mailer}#{SEPARATOR}#{action}"] = prepare_locals(*locals)
18
+ @mailers << mailer
19
+ end
20
+
21
+ def lookup(mailer, action)
22
+ @mapping["#{mailer}#{SEPARATOR}#{action}"] || {}
23
+ end
24
+
25
+ def populate!
26
+ Nisetegami::Template.find_each { |template| template.destroy unless action_exists?(template[:mailer], template.action) }
27
+
28
+ @mapping.each do |route, locals|
29
+ mailer, action = route.split(SEPARATOR, 2)
30
+ next unless can_populate?(mailer, action)
31
+ variables = expand_locals(*locals).map{ |v| "{{ #{v} }}" }.join(", ")
32
+
33
+ Nisetegami::Template.create!(
34
+ subject: "Subject",
35
+ body_text: "You can use following variables: #{variables}. Format: text.",
36
+ body_html: "You can use following variables: #{variables}. Format: html.",
37
+ name: route,
38
+ mailer: mailer,
39
+ action: action,
40
+ enabled: false
41
+ )
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def expand_locals(*locals)
48
+ locals.each_with_object([]) do |(v, thing), array|
49
+ meths = Nisetegami::Utils.liquid_methods_for(Nisetegami.cast[thing])
50
+ array << (meths.blank? ? v : meths.map { |m| "#{v}.#{m}" })
51
+ end.flatten
52
+ end
53
+
54
+ def prepare_locals(*locals)
55
+ options = locals.extract_options!
56
+ # need to call tableize because of the bug in classify method ('master_class'.classify => 'MasterClas')
57
+ locals.each_with_object({}) { |v, hsh| hsh[v.to_s] = v.to_s.tableize.classify }.merge(options.stringify_keys)
58
+ end
59
+
60
+ def can_populate?(mailer, action)
61
+ action_exists?(mailer, action) && !Nisetegami::Template.where(mailer: mailer, action: action).exists?
62
+ end
63
+
64
+ def action_exists?(mailer, action)
65
+ klass = mailer.constantize
66
+ klass.ancestors.include?(ActionMailer::Base) &&
67
+ klass.action_methods.include?(action.to_s)
68
+ rescue NameError
69
+ false
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,23 @@
1
+ if defined?(::FactoryGirl)
2
+
3
+ FactoryGirl.define do
4
+ factory :simple_nisetegami_template, class: 'Nisetegami::Template' do
5
+
6
+ mailer "Nisetegami::TestMailer"
7
+ sequence(:action) { |n| "simple_#{n}" }
8
+
9
+ subject "The quick brown {{ fox }} jumps over the lazy {{ dog }}."
10
+ body_text "The quick brown {{ fox }} jumps over the lazy {{ dog }}."
11
+ body_html "The quick brown {{ fox }} jumps over the lazy {{ dog }}."
12
+ layout_text "default"
13
+ layout_html "default"
14
+
15
+ after(:build) do |template|
16
+ Nisetegami::TestMailer.action_methods << template.action.to_sym
17
+ Nisetegami::TestMailer.send :alias_method, template.action.to_sym, :simple
18
+ Nisetegami.configure { |c| c.register template[:mailer], template.action, fox: 'String', dog: 'String' }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ class Nisetegami::TestMailer < ActionMailer::Base
2
+ def simple(fox, dog)
3
+ @fox = fox
4
+ @dog = dog
5
+ mail to: 'user@example.com'
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ Dir[File.expand_path('../test/*.rb', __FILE__)].each { |f| require f }
@@ -0,0 +1,15 @@
1
+ module Nisetegami
2
+ module Utils
3
+ module_function
4
+
5
+ def liquid_methods_for(thing)
6
+ return nil unless thing.const_defined?('LiquidDropClass')
7
+ thing::LiquidDropClass.public_instance_methods(false)
8
+ end
9
+
10
+ def filenames(path, format)
11
+ Dir[File.join(path, "*.#{format}.*")].map { |file| File.basename(file).sub(/\.#{format}#{File.extname(file)}$/, "") }.uniq
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Nisetegami
2
+ VERSION = "0.4.0"
3
+ end
data/lib/nisetegami.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'roadie'
2
+ require 'liquid'
3
+
4
+ require 'nisetegami/action_mailer_extensions'
5
+ require 'nisetegami/liquid_template_handler'
6
+ require 'nisetegami/ar_template_resolver'
7
+ require 'nisetegami/asset_provider'
8
+ require 'nisetegami/exceptions'
9
+ require 'nisetegami/mapping'
10
+ require 'nisetegami/utils'
11
+ require 'nisetegami/engine'
12
+
13
+ module Nisetegami
14
+
15
+ mattr_reader :layouts_path
16
+
17
+ mattr_reader :mapping
18
+ @@mapping = Nisetegami::Mapping.new
19
+
20
+ def self.configure
21
+ yield self
22
+ end
23
+
24
+ # optional block to cast a thing (String, Symbol)
25
+ # into a class with liquid_methods
26
+ def self.cast(&block)
27
+ @@cast ||= ->(thing){ defined?(thing) == 'constant' ? thing : thing.to_s.constantize }
28
+ block_given? ? @@cast = block : @@cast
29
+ end
30
+
31
+ def self.register(*args)
32
+ @@mapping.register(*args)
33
+ end
34
+
35
+ def self.populate!
36
+ @@mapping.populate!
37
+ end
38
+
39
+ class << self
40
+ %w(text html).each do |format|
41
+ define_method("#{format}_layouts") do
42
+ # cache result in class variable unless in development
43
+ instance_variable_get(:"@#{format}_layouts") || Nisetegami::Utils.filenames(Nisetegami.layouts_path, format).tap do |layouts|
44
+ instance_variable_set(:"@#{format}_layouts", layouts) unless Rails.env.development?
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :nisetegami do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,212 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nisetegami
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Denis Lifanov
9
+ - Dmitry Afanasyev
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-11-05 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '3.2'
31
+ - !ruby/object:Gem::Dependency
32
+ name: roadie
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: 2.3.1
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 2.3.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: liquid
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: sqlite3
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: rails
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: '3.2'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: '3.2'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rspec
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: factory_girl_rails
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: pry-debugger
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ description: ActiveRecord/Liquid-based mail templates, incl. CSS-processing.
160
+ email:
161
+ - inadsence@gmail.com
162
+ - dimarzio1986@gmail.com
163
+ executables: []
164
+ extensions: []
165
+ extra_rdoc_files: []
166
+ files:
167
+ - app/models/nisetegami/template.rb
168
+ - lib/generators/nisetegami/templates/migrations/001_create_nisetegami_templates.rb
169
+ - lib/generators/nisetegami/templates_generator.rb
170
+ - lib/nisetegami/action_mailer_extensions.rb
171
+ - lib/nisetegami/ar_template_resolver.rb
172
+ - lib/nisetegami/asset_provider.rb
173
+ - lib/nisetegami/engine.rb
174
+ - lib/nisetegami/exceptions.rb
175
+ - lib/nisetegami/liquid_template_handler.rb
176
+ - lib/nisetegami/mapping.rb
177
+ - lib/nisetegami/test/factories.rb
178
+ - lib/nisetegami/test/test_mailer.rb
179
+ - lib/nisetegami/test.rb
180
+ - lib/nisetegami/utils.rb
181
+ - lib/nisetegami/version.rb
182
+ - lib/nisetegami.rb
183
+ - lib/tasks/nisetegami_tasks.rake
184
+ - MIT-LICENSE
185
+ - Rakefile
186
+ - README.md
187
+ homepage: https://github.com/icrowley/nisetegami
188
+ licenses: []
189
+ post_install_message:
190
+ rdoc_options: []
191
+ require_paths:
192
+ - lib
193
+ required_ruby_version: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ none: false
201
+ requirements:
202
+ - - ! '>='
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ requirements: []
206
+ rubyforge_project:
207
+ rubygems_version: 1.8.24
208
+ signing_key:
209
+ specification_version: 3
210
+ summary: ActiveRecord/Liquid-based mail templates, incl. CSS-processing.
211
+ test_files: []
212
+ has_rdoc: