inkcite 1.10.0 → 1.11.0

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: 9bb7e08b66c836a2c76155628f8f95a6bc26fb8a
4
- data.tar.gz: 4861793716a8cffefea911601e915c6d9faf6fdc
3
+ metadata.gz: 7d4ec18570e9ba801f756e6594a3737bbc3ced90
4
+ data.tar.gz: df1c113816730b99cb4ced73b9c9965252ea4d97
5
5
  SHA512:
6
- metadata.gz: f0dee482e05a25f5a7be7acb9f10e21b05ee346c59ba4e5428fe78b36614da4e2c2883df544e85bf6b44f8d134c9a7f5831d9ea72f1f5a2001081aaedf2f75c3
7
- data.tar.gz: 38084033ae6eb914af1da477c6ceb803bf6025d02d9ced8e55a983247b416526e231805a78ccc9a3669ba81c7f930454bb73bce68a4a254b4b62d733dc4fd1da
6
+ metadata.gz: 143670d23d2712b7eddcc6e93358c9f3cf0155df60f6917d9258e1fc0c0be5dbc7bdde461ad15b035cc458e3cfe41f4bc5420cab295e44b87b65cc1efa45bab9
7
+ data.tar.gz: d6bf7f13e73984a4c85097c06074b26e85e6bb43c0c12b91f764b629cdbccdc3be312db47430377a1e5996c9ed6a934c9b38843210076c690358331dceb7c4ba
data/inkcite.gemspec CHANGED
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency 'mail'
37
37
  spec.add_dependency 'mailgun-ruby'
38
38
  spec.add_dependency 'net-sftp'
39
+ spec.add_dependency 'nokogiri'
39
40
  spec.add_dependency 'rack'
40
41
  spec.add_dependency 'rack-livereload'
41
42
  spec.add_dependency 'rubyzip'
@@ -113,6 +113,19 @@ module Inkcite
113
113
  options[:force] ? email.upload! : email.upload
114
114
  end
115
115
 
116
+ desc 'validate', 'Validate the email against W3C standards'
117
+ option :environment,
118
+ :aliases => '-e',
119
+ :default => 'production',
120
+ :desc => 'The environment (production, preview, development) to be Inkcite will run under'
121
+ option :version,
122
+ :aliases => '-v',
123
+ :desc => 'Preview a specific version of the email'
124
+ def validate
125
+ require_relative 'validate'
126
+ Cli::Validate.invoke(email, options)
127
+ end
128
+
116
129
  private
117
130
 
118
131
  # Resolves the desired environment (e.g. :development or :preview)
@@ -0,0 +1,70 @@
1
+ require 'nokogiri'
2
+
3
+ module Inkcite
4
+ module Cli
5
+ class Validate
6
+
7
+ def self.invoke email, opts
8
+
9
+ # True if all versions of the email are valid.
10
+ valid = true
11
+
12
+ # Grab the environment (e.g. production) that will be validated.
13
+ environment = opts[:environment]
14
+
15
+ # Check to see if a specific version is requested or if unspecified
16
+ # all versions of the email should be validated.
17
+ versions = Array(opts[:version] || email.versions)
18
+ versions.each do |version|
19
+
20
+ # The version of the email we will be sending.
21
+ view = email.view(environment, :email, version)
22
+
23
+ # Always disable minification
24
+ view.config[:minify] = false
25
+
26
+ subject = view.subject
27
+
28
+ print "Validating '#{subject}' ... "
29
+
30
+ source = view.render!
31
+
32
+ validator = Nokogiri::HTML(source) do |config|
33
+ config.strict
34
+ end
35
+
36
+ if validator.errors.any?
37
+ puts 'Invalid!'
38
+
39
+ lines = source.split(/\n/)
40
+
41
+ validator.errors.each do |err|
42
+ puts err.inspect
43
+ puts "#{err.line}: #{lines[err.line - 1]}"
44
+ puts [ err.column, err.int1, err.str1, err.str2, err.str3 ].inspect
45
+ end
46
+
47
+ else
48
+ puts 'Valid!'
49
+
50
+ end
51
+
52
+ if versions.length > 1
53
+ puts ''
54
+ end
55
+
56
+ end
57
+
58
+ valid
59
+ end
60
+
61
+ private
62
+
63
+ # Name of the config property that
64
+ TEST_ADDRESS = :'test-address'
65
+
66
+ end
67
+ end
68
+ end
69
+
70
+
@@ -23,6 +23,8 @@ require_relative 'renderer/outlook_background'
23
23
  require_relative 'renderer/partial'
24
24
  require_relative 'renderer/preheader'
25
25
  require_relative 'renderer/property'
26
+ require_relative 'renderer/redacted'
27
+ require_relative 'renderer/snow'
26
28
  require_relative 'renderer/span'
27
29
  require_relative 'renderer/table'
28
30
  require_relative 'renderer/td'
@@ -83,7 +85,16 @@ module Inkcite
83
85
 
84
86
  hash.keys.sort.each do |att|
85
87
  val = hash[att]
86
- pairs << "#{att}#{equal}#{val}" unless val.blank?
88
+ next if val.blank?
89
+
90
+ # First add the attribute name - e.g. "padding" or "bgcolor"
91
+ pair = "#{att}"
92
+
93
+ # Only append the value if the attribute value is a non-boolean.
94
+ # e.g. support boolean attributes via booleans ":nowrap => true"
95
+ pair << "#{equal}#{val}" unless val == true
96
+
97
+ pairs << pair
87
98
  end
88
99
 
89
100
  pairs.join(sep)
@@ -169,6 +180,8 @@ module Inkcite
169
180
  :'mobile-toggle-on' => MobileToggleOn.new,
170
181
  :'outlook-bg' => OutlookBackground.new,
171
182
  :preheader => Preheader.new,
183
+ :redacted => Redacted.new,
184
+ :snow => Snow.new,
172
185
  :span => Span.new,
173
186
  :table => Table.new,
174
187
  :td => Td.new
@@ -105,7 +105,7 @@ module Inkcite
105
105
  instance.active = true
106
106
 
107
107
  # Allow footnotes to be defined without showing a symbol
108
- hidden = opt[:hidden].to_i == 1
108
+ hidden = opt[:hidden] || (opt[:hidden] == '1')
109
109
  "#{instance.symbol}" unless hidden
110
110
  end
111
111
 
@@ -22,6 +22,12 @@ module Inkcite
22
22
  alt = opt[:alt]
23
23
  if alt
24
24
 
25
+ # Allow "\n" to be placed within alt text and converted into a line
26
+ # break for convenience. Need to add an extra space for the email
27
+ # clients (ahem, Gmail, cough) that don't support alt text with
28
+ # line breaks.
29
+ alt.gsub!('\n', "\n ")
30
+
25
31
  # Ensure that the alt-tag has quotes around it.
26
32
  img[:alt] = quote(alt)
27
33
 
@@ -14,15 +14,17 @@ module Inkcite
14
14
 
15
15
  # Always warn the creator that there is Lorem Ipsum in the email because
16
16
  # we don't want it to ship accidentally.
17
- ctx.error 'Email contains Lorem Ipsum'
17
+ ctx.error 'Email contains Lorem Ipsum' unless opt[:force]
18
18
 
19
19
  if type == :headline
20
-
21
20
  words = (limit || 4).to_i
22
21
  Faker::Lorem.words(words).join(SPACE).titlecase
23
22
 
24
- else
23
+ elsif type == :words
24
+ words = (limit || 7).to_i
25
+ Faker::Lorem.words(words).join(SPACE)
25
26
 
27
+ else
26
28
  sentences = (limit || 3).to_i
27
29
  Faker::Lorem.sentences(sentences).join(SPACE)
28
30
 
@@ -0,0 +1,27 @@
1
+ module Inkcite
2
+ module Renderer
3
+ class Redacted < Base
4
+
5
+ def render tag, opt, ctx
6
+
7
+ # Like Lorem Ipsum, warn the creator that there is redaction in
8
+ # the email unless the warn parameter is true.
9
+ ctx.error 'Email contains redacted content' unless opt[:force]
10
+
11
+ # The obscuring character defaults to 'x' but can be overridden
12
+ # using the 'with' attribute.
13
+ with = opt[:with] || 'x'
14
+
15
+ # Grab the text to be redacted, then apply the correct obscuring
16
+ # character based on the case of the original letters.
17
+ text = opt[:text]
18
+ text.gsub!(/[A-Z]/, with.upcase)
19
+ text.gsub!(/[a-z0-9]/, with.downcase)
20
+ text
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,270 @@
1
+ module Inkcite
2
+ module Renderer
3
+ class Snow < ContainerBase
4
+
5
+ # Ambient snow special effect renderer courtesy of
6
+ # http://freshinbox.com/blog/ambient-animations-in-email-snow-and-stars/
7
+ def render tag, opt, ctx
8
+
9
+ return '</div>' if tag == '/snow'
10
+
11
+ # Get a unique ID for this wrap element.
12
+ uid = ctx.unique_id(:snow)
13
+
14
+ # Total number of flakes to animate
15
+ flakes = (opt[:flakes] || 3).to_i
16
+
17
+ # This is the general class applied to all snow elements within this
18
+ # wrapping container.
19
+ all_flakes_class = ctx.development? ? "snow#{uid}-flakes" : "s#{uid}fs"
20
+ flake_prefix = ctx.development? ? "snow#{uid}-flake" : "s#{uid}f"
21
+ anim_prefix = ctx.development? ? "snow#{uid}-anim" : "s#{uid}a"
22
+
23
+ # Grab the min and max sizes for the flakes or inherit default values.
24
+ flake_min_size = (opt[FLAKE_SIZE_MIN] || 6).to_i
25
+ flake_max_size = (opt[FLAKE_SIZE_MAX] || 18).to_i
26
+
27
+ # Grab the min and max speeds for the flakes, the smaller the value the
28
+ # faster the flake moves.
29
+ flake_min_speed = (opt[FLAKE_SPEED_MIN] || 3).to_f
30
+ flake_max_speed = (opt[FLAKE_SPEED_MAX] || 8).to_f
31
+
32
+ # Determine the spread of the flakes - the bigger the spread, the larger
33
+ # the variance between where the flake starts and where it ends.
34
+ # Measured in %-width of the overall area.
35
+ spread = (opt[:spread] || 20).to_i
36
+ half_spread = spread / 2.0
37
+
38
+ # Determine the opacity variance.
39
+ flake_min_opacity = (opt[FLAKE_OPACITY_MIN] || 0.5).to_f
40
+ flake_max_opacity = (opt[FLAKE_OPACITY_MAX] || 0.9).to_f
41
+
42
+ # Overall time for the initial distribution of flakes.
43
+ end_time = (opt[:time] || 4).to_f
44
+
45
+ # Setup some ranges for easier random numbering.
46
+ size_range = (flake_min_size..flake_max_size)
47
+ speed_range = (flake_min_speed..flake_max_speed)
48
+ spread_range = (-half_spread..half_spread)
49
+ opacity_range = (flake_min_opacity..flake_max_opacity)
50
+
51
+ # Snowflake color.
52
+ color = hex(opt[:color] || '#fff')
53
+
54
+ # Check to see if a source image has been specified for the snowflakes.
55
+ src = opt[:src]
56
+
57
+ # If the image is missing, record an error to the console and
58
+ # clear the image allowing the color to take precedence instead.
59
+ src = nil unless ctx.assert_image_exists(src)
60
+
61
+ # Flake rotation, used if an image is present. (Rotating a colored
62
+ # circle has no visual distinction.) For convenience this tag accepts
63
+ # boolean rotate and rotation
64
+ rotation_enabled = src && (opt[:rotate] || opt[:rotation])
65
+
66
+ # Initialize the wrap that will hold each of the snowflakes and the
67
+ # content within that will have it's
68
+ div_wrap = Element.new('div')
69
+
70
+ # Resolve the wrapping class name - readable name in development,
71
+ # space-saving name in all other environments.
72
+ wrap_class = ctx.development? ? "snow#{uid}-wrap" : "s#{uid}w"
73
+ div_wrap[:class] = wrap_class
74
+
75
+ # Background color gets applied directly to the div so it renders
76
+ # consistently in all clients - even those that don't support the
77
+ # snow effect.
78
+ mix_background div_wrap, opt, ctx
79
+
80
+ # Kick things off by rendering the wrapping div.
81
+ html = div_wrap.to_s
82
+
83
+ # Get the number of flakes that should be included. Create a child div for
84
+ # each flake that can be sized, animated uniquely.
85
+ flakes.times do |flake|
86
+ html << %Q(<div class="#{all_flakes_class} #{flake_prefix}#{flake + 1}"></div>)
87
+ end
88
+
89
+ # Check to see if there is a height required for the wrap element - otherwise
90
+ # the wrap will simply enlarge to hold all of the contents within.
91
+ wrap_height = opt[:height].to_i
92
+
93
+ # Will hold all of the styles as they're assembled.
94
+ style = []
95
+
96
+ # True if we're limiting the animation to webkit only. In development
97
+ # or in the browser version of the email, the animation should be as
98
+ # compatible as possible but in all other cases it should be webkit only.
99
+ webkit_only = !(ctx.development? || ctx.browser?)
100
+
101
+ # Hide the snow effect from any non-webkit email clients.
102
+ style << '@media screen and (-webkit-min-device-pixel-ratio: 0) {' if webkit_only
103
+
104
+ # Snow wrapping element in-which the snow flakes will be animated.
105
+ style << " .#{wrap_class} {"
106
+ style << ' position: relative;'
107
+ style << ' overflow: hidden;'
108
+ style << ' width: 100%;'
109
+ style << " height: #{px(wrap_height)};" if wrap_height > 0
110
+ style << ' }'
111
+
112
+ # Common attributes for all snowflakes.
113
+ style << " .#{all_flakes_class} {"
114
+ style << ' position: absolute;'
115
+ style << " top: -#{flake_max_size + 4}px;"
116
+
117
+ # If no image has been provided, make the background a solid color
118
+ # otherwise set the background to the image source and fill the
119
+ # available space.
120
+ if src.blank?
121
+ style << " background-color: #{color};"
122
+ else
123
+ style << " background-image: url(#{ctx.image_url(src)});"
124
+ style << " background-size: 100%;"
125
+ end
126
+
127
+ style << ' }'
128
+
129
+ # Space the snowflakes generally equally across the width of the
130
+ # container div. Random distribution sometimes ends up with
131
+ # snowflakes clumped at one edge or the other.
132
+ flake_spacing = 100 / flakes.to_f
133
+
134
+ # Now build up a pool of equally-spaced starting positions.
135
+ # TODO: This is probably a perfect spot to use inject()
136
+ start_left = flake_spacing / 2.0
137
+ start_positions = [start_left]
138
+ (flakes - 1).times { |f| start_positions << start_left += flake_spacing }
139
+
140
+ # Randomize the starting positions - otherwise they draw right-to-left
141
+ # as starting positions are popped from the pool.
142
+ start_positions.shuffle!
143
+
144
+ # Snowflakes will be dispersed equally across the total time
145
+ # of the animation making for a smoother, more balanced show.
146
+ start_interval = end_time / flakes.to_f
147
+ start_time = 0
148
+
149
+ # Now add individual class definitions for each flake with unique size,
150
+ # speed and starting position. Also add the animation trigger that loops
151
+ # infinitely, starts at a random time and uses a random speed to completion.
152
+ flakes.times do |flake|
153
+
154
+ speed = rand(speed_range).round(1)
155
+ size = rand(size_range)
156
+
157
+ opacity = rand(opacity_range).round(1)
158
+ if opacity < OPACITY_FLOOR
159
+ opacity = OPACITY_FLOOR
160
+ elsif opacity > OPACITY_CEIL
161
+ opacity = OPACITY_CEIL
162
+ end
163
+
164
+ style << " .#{flake_prefix}#{flake + 1} {"
165
+ style << " height: #{px(size)};"
166
+ style << " width: #{px(size)};"
167
+
168
+ # Only apply a border radius if the snowflake lacks an image.
169
+ style << " border-radius: #{px((size / 2.0).round)};" unless src
170
+
171
+ style << " opacity: #{opacity};" if opacity < OPACITY_CEIL
172
+ style << with_browser_prefixes(' ', "animation: #{anim_prefix}#{flake + 1} #{speed}s linear #{start_time.round(1)}s infinite;", webkit_only)
173
+ style << ' }'
174
+
175
+ start_time += start_interval
176
+ end
177
+
178
+ # Declare each of the flake animations.
179
+ flakes.times do |flake|
180
+
181
+ start_left = start_positions.pop
182
+
183
+ # Randomly choose where the snow will end its animation. Prevent
184
+ # it from going outside of the container.
185
+ end_left = (start_left + rand(spread_range)).round
186
+ if end_left < POSITION_FLOOR
187
+ end_left = POSITION_FLOOR
188
+ elsif end_left > POSITION_CEIL
189
+ end_left = POSITION_CEIL
190
+ end
191
+
192
+ # Calculate the ending rotation for the flake, if rotation is enabled.
193
+ end_rotation = rotation_enabled ? rand(ROTATION_RANGE) : 0
194
+
195
+ _style = "keyframes #{anim_prefix}#{flake + 1} {\n"
196
+ _style << " 0% { top: -3%; left: #{start_left}%; }\n"
197
+ _style << " 100% { top: 100%; left: #{end_left}%;"
198
+ _style << with_browser_prefixes(' ', "transform: rotate(#{end_rotation}deg);", webkit_only, '') if end_rotation != 0
199
+ _style << " }\n"
200
+ _style << ' }'
201
+
202
+ style << with_browser_prefixes(" @", _style, webkit_only)
203
+
204
+ end
205
+
206
+ style << '}' if webkit_only
207
+
208
+ ctx.styles << style.join("\n")
209
+
210
+ html
211
+
212
+ end
213
+
214
+ private
215
+
216
+ # Renders the CSS with the appropriate browser prefixes based
217
+ # on whether or not this version of the email is webkit only.
218
+ def with_browser_prefixes indentation, css, webkit_only, separator="\n"
219
+
220
+ # Determine which prefixes will be applied.
221
+ browser_prefixes = webkit_only ? WEBKIT_BROWSERS : ALL_BROWSERS
222
+
223
+ # This will hold the completed CSS with all prefixes applied.
224
+ _css = ''
225
+
226
+ # Iterate through the prefixes and apply them with the indentation
227
+ # and CSS declaration with line breaks.
228
+ browser_prefixes.each do |prefix|
229
+ _css << indentation
230
+ _css << prefix
231
+ _css << css
232
+ _css << separator
233
+ end
234
+
235
+ _css
236
+ end
237
+
238
+ # Size constraints on the flakes.
239
+ FLAKE_SIZE_MIN = :'min-size'
240
+ FLAKE_SIZE_MAX = :'max-size'
241
+
242
+ # Speed constraints on the flakes.
243
+ FLAKE_SPEED_MIN = :'min-speed'
244
+ FLAKE_SPEED_MAX = :'max-speed'
245
+
246
+ # Opacity constraints.
247
+ FLAKE_OPACITY_MIN = :'min-opacity'
248
+ FLAKE_OPACITY_MAX = :'max-opacity'
249
+ OPACITY_FLOOR = 0.2
250
+ OPACITY_CEIL = 1.0
251
+
252
+ # Rotation angles when image rotation is enabled.
253
+ ROTATION_RANGE = (-270..270)
254
+
255
+ # Position min and max preventing snow flakes
256
+ # from leaving the bounds of the container.
257
+ POSITION_FLOOR = 0
258
+ POSITION_CEIL = 100
259
+
260
+ # Static arrays with browser prefixes. Turns out that
261
+ # Firefox, IE and Opera don't require a prefix so to
262
+ # target everything we need the non-prefixed version
263
+ # (hence the blank entry) plus the webkit prefix.
264
+ WEBKIT_BROWSERS = ['-webkit-']
265
+ ALL_BROWSERS = [''] + WEBKIT_BROWSERS
266
+
267
+ end
268
+
269
+ end
270
+ end
@@ -68,6 +68,9 @@ module Inkcite
68
68
  padding = get_padding(table_opt)
69
69
  td.style[:padding] = px(padding) if padding > 0
70
70
 
71
+ # Apply the no-wrap attribute if provided.
72
+ td[:nowrap] = true if opt[:nowrap]
73
+
71
74
  mobile = opt[:mobile]
72
75
 
73
76
  # Need to handle Fluid-Drop HTML injection here before the rest of the
@@ -1,3 +1,3 @@
1
1
  module Inkcite
2
- VERSION = "1.10.0"
2
+ VERSION = "1.11.0"
3
3
  end
data/lib/inkcite/view.rb CHANGED
@@ -841,7 +841,7 @@ module Inkcite
841
841
  path = @email.path
842
842
  file = File.join(path, filename)
843
843
  unless File.exists?(file)
844
- abort("Can't find #{filename} in #{path} - are you sure this is an Inkcite project?") if abort_on_fail
844
+ error("Unable to load helper file", :file => file) if abort_on_fail
845
845
  return
846
846
  end
847
847
 
@@ -893,6 +893,11 @@ module Inkcite
893
893
  :n => NEW_LINE
894
894
  }
895
895
 
896
+ # Check to see if the config.yml includes a "helpers:" array which allows
897
+ # additional out-of-project, shared helper files to be loaded.
898
+ included_helpers = [*@email.config[:helpers]]
899
+ included_helpers.each { |file| load_helper_file(file, _helpers) }
900
+
896
901
  # Load the project's properties, which may include references to additional
897
902
  # properties in other directories.
898
903
  load_helper_file 'helpers.tsv', _helpers
@@ -50,7 +50,7 @@ describe Inkcite::Renderer::Footnote do
50
50
  end
51
51
 
52
52
  it 'can be defined silently' do
53
- Inkcite::Renderer.render('{footnote hidden=1 text="EPA-estimated fuel economy."}{footnotes}', @view).must_equal("<sup>1</sup> EPA-estimated fuel economy.<br><br>\n")
53
+ Inkcite::Renderer.render('{footnote hidden text="EPA-estimated fuel economy."}{footnotes}', @view).must_equal("<sup>1</sup> EPA-estimated fuel economy.<br><br>\n")
54
54
  end
55
55
 
56
56
  it 'converts "\n" within footnotes template to new-lines' do
@@ -0,0 +1,25 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'inkcite'
4
+
5
+ describe Inkcite::Renderer::Lorem do
6
+
7
+ before do
8
+ @view = Inkcite::Email.new('test/project/').view(:development, :email)
9
+ end
10
+
11
+ it 'produces placeholder text' do
12
+ Inkcite::Renderer.render('{lorem}', @view).wont_equal('')
13
+ end
14
+
15
+ it 'triggers an error when included' do
16
+ Inkcite::Renderer.render('{lorem}', @view)
17
+ @view.errors.must_include('Email contains Lorem Ipsum (line 0)')
18
+ end
19
+
20
+ it 'does not trigger an error when included and forced' do
21
+ Inkcite::Renderer.render('{lorem force}', @view)
22
+ @view.errors.must_be_nil
23
+ end
24
+
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'inkcite'
4
+
5
+ describe Inkcite::Renderer::Redacted do
6
+
7
+ before do
8
+ @view = Inkcite::Email.new('test/project/').view(:development, :email)
9
+ end
10
+
11
+ it 'renders redacted content' do
12
+ Inkcite::Renderer.render('{redacted text="This Is Redacted Text."}', @view).must_equal('Xxxx Xx Xxxxxxxx Xxxx.')
13
+ end
14
+
15
+ it 'triggers an error when included' do
16
+ Inkcite::Renderer.render('{redacted text="This is redacted text."}', @view)
17
+ @view.errors.must_include('Email contains redacted content (line 0)')
18
+ end
19
+
20
+ it 'does not trigger an error when included and forced' do
21
+ Inkcite::Renderer.render('{redacted force text="This is redacted text."}', @view)
22
+ @view.errors.must_be_nil
23
+ end
24
+
25
+ end
@@ -127,4 +127,8 @@ describe Inkcite::Renderer::Td do
127
127
  @view.media_query.find_by_klass('m1').to_css.must_equal('td[class~="m1"] { background:none !important }')
128
128
  end
129
129
 
130
+ it 'supports nowrap' do
131
+ Inkcite::Renderer.render('{td nowrap}', @view).must_equal('<td nowrap>')
132
+ end
133
+
130
134
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inkcite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeffrey D. Hoffman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-07 00:00:00.000000000 Z
11
+ date: 2016-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - '>='
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: nokogiri
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: rack
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -336,6 +350,7 @@ files:
336
350
  - lib/inkcite/cli/scope.rb
337
351
  - lib/inkcite/cli/server.rb
338
352
  - lib/inkcite/cli/test.rb
353
+ - lib/inkcite/cli/validate.rb
339
354
  - lib/inkcite/email.rb
340
355
  - lib/inkcite/mailer.rb
341
356
  - lib/inkcite/minifier.rb
@@ -363,7 +378,9 @@ files:
363
378
  - lib/inkcite/renderer/partial.rb
364
379
  - lib/inkcite/renderer/preheader.rb
365
380
  - lib/inkcite/renderer/property.rb
381
+ - lib/inkcite/renderer/redacted.rb
366
382
  - lib/inkcite/renderer/responsive.rb
383
+ - lib/inkcite/renderer/snow.rb
367
384
  - lib/inkcite/renderer/span.rb
368
385
  - lib/inkcite/renderer/table.rb
369
386
  - lib/inkcite/renderer/table_base.rb
@@ -389,8 +406,10 @@ files:
389
406
  - test/renderer/footnote_spec.rb
390
407
  - test/renderer/image_spec.rb
391
408
  - test/renderer/link_spec.rb
409
+ - test/renderer/lorem_spec.rb
392
410
  - test/renderer/mobile_image_spec.rb
393
411
  - test/renderer/mobile_style_spec.rb
412
+ - test/renderer/redacted_spec.rb
394
413
  - test/renderer/span_spec.rb
395
414
  - test/renderer/table_spec.rb
396
415
  - test/renderer/td_spec.rb
@@ -435,8 +454,10 @@ test_files:
435
454
  - test/renderer/footnote_spec.rb
436
455
  - test/renderer/image_spec.rb
437
456
  - test/renderer/link_spec.rb
457
+ - test/renderer/lorem_spec.rb
438
458
  - test/renderer/mobile_image_spec.rb
439
459
  - test/renderer/mobile_style_spec.rb
460
+ - test/renderer/redacted_spec.rb
440
461
  - test/renderer/span_spec.rb
441
462
  - test/renderer/table_spec.rb
442
463
  - test/renderer/td_spec.rb