inkcite 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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