roadie 3.3.0 → 3.4.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: 2a5d2f3eb66ab40ecf551f53e5b7df59321c2805
4
- data.tar.gz: 82c0b5241461df56c8810dca075245a75a0acf99
3
+ metadata.gz: a2c4863b0337cfe2129ee5e1184bb3ffdd422ea9
4
+ data.tar.gz: ccd82152f99fe3131773f9070ef39c07952027d2
5
5
  SHA512:
6
- metadata.gz: e8c1a2ed3e74d586b95e341472b4c80e18e58ae01a094955b7dc102cd2cfe7c76ec1172159e1a1138a09adea465ac17ca1b0fcbde1f42680c46252cffee977ec
7
- data.tar.gz: 777552240c002247354dad9c1bcc6ac6fb78ab62774d7e4fb3fe2e1a7aa49f855a67f3586b0178d0b99455c5d0e9547d72d3a30f460e3f8ecec6cabd9f437125
6
+ metadata.gz: 8acd0f1029e3b40c94fe11e465b6604f6f16aca3d6a33375f14e3c2ea8ded36ca45edbf29e09fe3408c1ac21632875e92093fd8bce17f72658c3a9d9112b8087
7
+ data.tar.gz: e66923f904d221f10731bf92058390106ebcbf16be9a9053c149c41919252862285e53d86eec93fc4ececaef894b4ec9df019ad5c23678fa3eabed7ab3676d27
data/.gitignore CHANGED
@@ -8,3 +8,6 @@ Gemfile.lock
8
8
  doc
9
9
  tmp
10
10
  pkg
11
+ .bundle
12
+ .history
13
+ vendor/
@@ -20,5 +20,4 @@ matrix:
20
20
  - rvm: rbx
21
21
  fast_finish: true
22
22
  cache: bundler
23
- bundler_args: --without guard
24
23
  script: "rake"
@@ -1,10 +1,30 @@
1
1
  ### dev
2
2
 
3
- [full changelog](https://github.com/Mange/roadie/compare/v3.3.0...master)
3
+ [full changelog](https://github.com/Mange/roadie/compare/v3.4.0...master)
4
4
 
5
- * Nothing yet.
5
+ Nothing yet.
6
6
 
7
- ### 3.2.2
7
+ ### 3.3.0
8
+
9
+ [full changelog](https://github.com/Mange/roadie/compare/v3.3.0...v3.4.0)
10
+
11
+ * Enhancements
12
+ * Better support for media queries - [BroiSatse (Stanislaw
13
+ Klajn)](https://github.com/BroiSatse) and [jeznag (Jeremy
14
+ Nagel)](https://github.com/jeznag) (#157).
15
+
16
+ Media queries should no longer be inlined in your HTML; instead they should
17
+ appear in `<head>` if `keep_uninlinable_css` is enabled. By default different
18
+ media query blocks with the same conditions will be merged together (which
19
+ might change specificity), but this behavior can be disabled by setting
20
+ `merge_media_queries` to `false`.
21
+
22
+ * Remove Guard as a development dependency. Tests run fast anyway, and I
23
+ never liked that this tool "infected" the dependencies of the project when
24
+ it should remain a user-specific tool unless the project wants to enforce
25
+ it.
26
+
27
+ ### 3.3.0
8
28
 
9
29
  [full changelog](https://github.com/Mange/roadie/compare/v3.2.2...v3.3.0)
10
30
 
@@ -12,7 +32,7 @@
12
32
  * Allow transforming to XHTML instead of HTML - [Zhivko Draganov](https://github.com/zdraganov) (#144).
13
33
  * Support partial HTML documents (fragments) - #147
14
34
  * With the help of [andfx](https://github.com/andfx) - #115
15
- * With the help of [Frida Sjoholm](https://github.com/andf://github.com/FridaSjoholm) - #146
35
+ * With the help of [Frida Sjoholm](https://github.com/FridaSjoholm) - #146
16
36
  * Skip URL rewriting on elements with `data-roadie-ignore` - #154.
17
37
  * With the help of [Hamed Asghari](https://github.com/hasghari) - #138.
18
38
  * Bug fixes:
data/Gemfile CHANGED
@@ -3,8 +3,3 @@ gemspec
3
3
 
4
4
  # Added here so it does not show up on the Gemspec; I only want it for CI builds
5
5
  gem 'codecov', group: :test, require: false
6
-
7
- group :guard do
8
- gem 'guard'
9
- gem 'guard-rspec'
10
- end
data/README.md CHANGED
@@ -4,9 +4,13 @@ Roadie
4
4
  [![Build history and status](https://travis-ci.org/Mange/roadie.svg?branch=master)](http://travis-ci.org/#!/Mange/roadie)
5
5
  [![Code Climate](https://codeclimate.com/github/Mange/roadie.png)](https://codeclimate.com/github/Mange/roadie)
6
6
  [![Code coverage status](https://codecov.io/github/Mange/roadie/coverage.svg?branch=master)](https://codecov.io/github/Mange/roadie?branch=master)
7
- [![Gem Version](https://badge.fury.io/rb/roadie.png)](http://badge.fury.io/rb/roadie)
7
+ [![Gem](https://img.shields.io/gem/v/roadie.svg)](https://rubygems.org/gems/roadie)
8
+ [![Passive maintenance](https://img.shields.io/badge/maintenance-Passive-yellow.svg)][passive]
8
9
 
9
- **Note: This README details the 3.x version of Roadie. You might be using 2.x, which is much older and only for Rails.**
10
+
11
+ |||
12
+ |---|---|
13
+ | :warning: | This gem is now in [passive maintenance mode][passive]. [(more)][passive] |
10
14
 
11
15
  > Making HTML emails comfortable for the Ruby rockstars
12
16
 
@@ -35,7 +39,7 @@ Features
35
39
  * Respects `!important` styles.
36
40
  * Does not overwrite styles already present in the `style` attribute of tags.
37
41
  * Supports the same CSS selectors as [Nokogiri](http://nokogiri.org/); use CSS3 selectors in your emails!
38
- * Keeps `:hover` and friends around in a separate `<style>` element.
42
+ * Keeps `:hover`, `@media { ... }` and friends around in a separate `<style>` element.
39
43
  * Makes image urls absolute.
40
44
  * Hostname and port configurable on a per-environment basis.
41
45
  * Can be disabled on individual elements.
@@ -51,7 +55,7 @@ Install & Usage
51
55
  [Add this gem to your Gemfile as recommended by Rubygems](http://rubygems.org/gems/roadie) and run `bundle install`.
52
56
 
53
57
  ```ruby
54
- gem 'roadie', '~> 3.2'
58
+ gem 'roadie', '~> 3.4'
55
59
  ```
56
60
 
57
61
  You can then create a new instance of a Roadie document:
@@ -74,6 +78,19 @@ Your document instance can be configured with several options:
74
78
 
75
79
  * `url_options` - Dictates how absolute URLs should be built.
76
80
  * `keep_uninlinable_css` - Set to false to skip CSS that cannot be inlined.
81
+ * `merge_media_queries` - Set to false to not group media queries. Some users might prefer to not group rules within media queries because
82
+ it will result in rules getting reordered.
83
+ e.g.
84
+ ```css
85
+ @media(max-width: 600px) { .col-6 { display: block; } }
86
+ @media(max-width: 400px) { .col-12 { display: inline-block; } }
87
+ @media(max-width: 600px) { .col-12 { display: block; } }
88
+ ```
89
+ will become
90
+ ```css
91
+ @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
92
+ @media(max-width: 400px) { .col-12 { display: inline-block; } }
93
+ ```
77
94
  * `asset_providers` - A list of asset providers that are invoked when CSS files are referenced. See below.
78
95
  * `external_asset_providers` - A list of asset providers that are invoked when absolute CSS URLs are referenced. See below.
79
96
  * `before_transformation` - A callback run before transformation starts.
@@ -464,6 +481,12 @@ Instructions on how to do this on most platforms, see [Nokogiri's official insta
464
481
 
465
482
  The CSS Parser used in Roadie does not handle keyframes. I don't think any email clients do either, but if you want to keep on trying you can add them manually to a `<style>` element (or a separate referenced stylesheet) and [tell Roadie not to touch them](#referenced-stylesheets).
466
483
 
484
+ ### My `@media` queries are reordered, how can I fix this?
485
+
486
+ Different `@media` query blocks with the same conditions are merged by default,
487
+ which will change the order in some cases. You can disable this by setting
488
+ `merge_media_queries` to `false`. (See *Install & Usage* section above).
489
+
467
490
  ### How do I get rid of the `<body>` elements that are added?
468
491
 
469
492
  It sounds like you want to transform a partial document. Maybe you are building
@@ -553,3 +576,4 @@ The above copyright notice and this permission notice shall be included in all c
553
576
  THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
554
577
 
555
578
  [gpg]: https://gist.github.com/Mange/baf25e23e653a206ec2d#file-keybase-md
579
+ [passive]: https://github.com/Mange/roadie/issues/155
@@ -29,12 +29,24 @@ module Roadie
29
29
  # Should CSS that cannot be inlined be kept in a new `<style>` element in `<head>`?
30
30
  attr_accessor :keep_uninlinable_css
31
31
 
32
+ # Merge media queries to increase performance and reduce email size if enabled.
33
+ # This will change specificity in some cases, like for example:
34
+ # @media(max-width: 600px) { .col-6 { display: block; } }
35
+ # @media(max-width: 400px) { .col-12 { display: inline-block; } }
36
+ # @media(max-width: 600px) { .col-12 { display: block; } }
37
+ # will become
38
+ # @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
39
+ # @media(max-width: 400px) { .col-12 { display: inline-block; } }
40
+ # which would change the styling on the page
41
+ attr_accessor :merge_media_queries
42
+
32
43
  # The mode to generate markup in. Valid values are `:html` (default) and `:xhtml`.
33
44
  attr_reader :mode
34
45
 
35
46
  # @param [String] html the input HTML
36
47
  def initialize(html)
37
48
  @keep_uninlinable_css = true
49
+ @merge_media_queries = true
38
50
  @html = html
39
51
  @asset_providers = ProviderList.wrap(FilesystemProvider.new)
40
52
  @external_asset_providers = ProviderList.empty
@@ -154,6 +166,7 @@ module Roadie
154
166
  Inliner.new(dom_stylesheets + [stylesheet], dom).inline(
155
167
  keep_uninlinable_css: keep_uninlinable_css,
156
168
  keep_uninlinable_in: keep_uninlinable_in,
169
+ merge_media_queries: merge_media_queries,
157
170
  )
158
171
  end
159
172
 
@@ -26,17 +26,19 @@ module Roadie
26
26
  #
27
27
  # @option options [true, false] :keep_uninlinable_css
28
28
  # @option options [:root, :head] :keep_uninlinable_in
29
+ # @option options [true, false] :merge_media_queries
29
30
  # @return [nil]
30
31
  def inline(options = {})
31
32
  keep_uninlinable_css = options.fetch(:keep_uninlinable_css, true)
32
33
  keep_uninlinable_in = options.fetch(:keep_uninlinable_in, :head)
34
+ merge_media_queries = options.fetch(:merge_media_queries, true)
33
35
 
34
36
  style_map, extra_blocks = consume_stylesheets
35
37
 
36
38
  apply_style_map(style_map)
37
39
 
38
40
  if keep_uninlinable_css
39
- add_uninlinable_styles(keep_uninlinable_in, extra_blocks)
41
+ add_uninlinable_styles(keep_uninlinable_in, extra_blocks, merge_media_queries)
40
42
  end
41
43
 
42
44
  nil
@@ -96,7 +98,12 @@ module Roadie
96
98
  nil
97
99
  end
98
100
 
99
- def add_uninlinable_styles(parent, blocks)
101
+ # Adds unlineable styles in the specified part of the document
102
+ # either the head or in the document
103
+ # @param [Symbol] parent Where to put the styles
104
+ # @param [Array<StyleBlock>] blocks Non-inlineable style blocks
105
+ # @param [Boolean] merge_media_queries Whether to group media queries
106
+ def add_uninlinable_styles(parent, blocks, merge_media_queries)
100
107
  return if blocks.empty?
101
108
 
102
109
  parent_node =
@@ -109,28 +116,80 @@ module Roadie
109
116
  raise ArgumentError, "Parent must be either :head or :root. Was #{parent.inspect}"
110
117
  end
111
118
 
112
- create_style_element(blocks, parent_node)
119
+ create_style_element(blocks, parent_node, merge_media_queries)
113
120
  end
114
121
 
115
122
  def find_head
116
123
  dom.at_xpath('html/head')
117
124
  end
118
125
 
119
- def create_style_element(style_blocks, parent)
126
+ def create_style_element(style_blocks, parent, merge_media_queries)
120
127
  return unless parent
121
- element = Nokogiri::XML::Node.new("style", parent.document)
122
- element.content = style_blocks.join("\n")
128
+ element = Nokogiri::XML::Node.new('style', parent.document)
129
+
130
+ element.content =
131
+ if merge_media_queries
132
+ styles_in_shared_media_queries(style_blocks).join("\n")
133
+ else
134
+ styles_in_individual_media_queries(style_blocks).join("\n")
135
+ end
123
136
  parent.add_child(element)
124
137
  end
125
138
 
139
+ # For performance reasons, we should group styles with the same media types within
140
+ # one media query instead of creating thousands of media queries.
141
+ # https://github.com/artifex404/media-queries-benchmark
142
+ # Example result: ["@media(max-width: 600px) { .col-12 { display: block; } }"]
143
+ # @param {Array<StyleBlock>} style_blocks Style blocks that could not be inlined
144
+ # @return {Array<String>}
145
+ def styles_in_shared_media_queries(style_blocks)
146
+ style_blocks.group_by(&:media).map do |media_types, blocks|
147
+ css_rules = blocks.map(&:to_s).join("\n")
148
+
149
+ if media_types == ['all']
150
+ css_rules
151
+ else
152
+ "@media #{media_types.join(', ')} {\n#{css_rules}\n}"
153
+ end
154
+ end
155
+ end
156
+
157
+ # Some users might prefer to not group rules within media queries because
158
+ # it will result in rules getting reordered.
159
+ # e.g.
160
+ # @media(max-width: 600px) { .col-6 { display: block; } }
161
+ # @media(max-width: 400px) { .col-12 { display: inline-block; } }
162
+ # @media(max-width: 600px) { .col-12 { display: block; } }
163
+ # will become
164
+ # @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
165
+ # @media(max-width: 400px) { .col-12 { display: inline-block; } }
166
+ # which would change the styling on the page
167
+ # (before it would've yielded display: block; for .col-12 at max-width: 600px
168
+ # and now it yields inline-block;)
169
+ #
170
+ # If merge_media_queries is set to false,
171
+ # we will generate #{style_blocks.size} media queries, potentially
172
+ # causing performance issues.
173
+ # @param {Array<StyleBlock>} style_blocks All style blocks
174
+ # @return {Array<String>}
175
+ def styles_in_individual_media_queries(style_blocks)
176
+ style_blocks.map do |css_rule|
177
+ if css_rule.media == ['all']
178
+ css_rule
179
+ else
180
+ "@media #{css_rule.media.join(', ')} {\n#{css_rule}\n}"
181
+ end
182
+ end
183
+ end
184
+
126
185
  # @api private
127
186
  # StyleMap is a map between a DOM element and {StyleAttributeBuilder}. Basically,
128
187
  # it's an accumulator for properties, scoped on specific elements.
129
188
  class StyleMap
130
189
  def initialize
131
- @map = Hash.new { |hash, key|
190
+ @map = Hash.new do |hash, key|
132
191
  hash[key] = StyleAttributeBuilder.new
133
- }
192
+ end
134
193
  end
135
194
 
136
195
  def add(elements, new_properties)
@@ -5,28 +5,49 @@ module Roadie
5
5
  # A style block is the combination of a {Selector} and a list of {StyleProperty}.
6
6
  class StyleBlock
7
7
  extend Forwardable
8
- attr_reader :selector, :properties
8
+ attr_reader :selector, :properties, :media
9
9
 
10
10
  # @param [Selector] selector
11
11
  # @param [Array<StyleProperty>] properties
12
- def initialize(selector, properties)
12
+ # @param [Array<String>] media Array of media types, e.g.
13
+ # @media screen, print and (max-width 800px) will become
14
+ # ['screen', 'print and (max-width 800px)']
15
+ def initialize(selector, properties, media)
13
16
  @selector = selector
14
17
  @properties = properties
18
+ @media = media.map(&:to_s)
15
19
  end
16
20
 
17
21
  # @!method specificity
18
22
  # @see Selector#specificity
19
- # @!method inlinable?
20
- # @see Selector#inlinable?
21
- def_delegators :selector, :specificity, :inlinable?
23
+ def_delegators :selector, :specificity
22
24
  # @!method selector_string
23
25
  # @see Selector#to_s
24
26
  def_delegator :selector, :to_s, :selector_string
25
27
 
28
+ # Checks whether the media query can be inlined
29
+ # @see inlineable_media
30
+ # @return {Boolean}
31
+ def inlinable?
32
+ inlinable_media? && selector.inlinable?
33
+ end
34
+
26
35
  # String representation of the style block. This is valid CSS and can be
27
36
  # used in the DOM.
37
+ # @return {String}
28
38
  def to_s
39
+ # NB - leave off redundant final semicolon - see https://www.w3.org/TR/CSS2/syndata.html#declaration
29
40
  "#{selector}{#{properties.map(&:to_s).join(';')}}"
30
41
  end
42
+
43
+ private
44
+
45
+ # A media query cannot be inlined if it contains any advanced rules
46
+ # e.g. @media only screen {...} is ok to inline but
47
+ # @media only screen and (max-width: 600px) {...} cannot be inlined
48
+ # @return {Boolean}
49
+ def inlinable_media?
50
+ @media.none? { |media_query| media_query.include? '(' }
51
+ end
31
52
  end
32
53
  end
@@ -43,17 +43,16 @@ module Roadie
43
43
  def parse_blocks(css)
44
44
  blocks = []
45
45
  parser = setup_parser(css)
46
-
47
46
  parser.each_rule_set do |rule_set, media_types|
48
47
  rule_set.selectors.each do |selector_string|
49
- blocks << create_style_block(selector_string, rule_set)
48
+ blocks << create_style_block(selector_string, rule_set, media_types)
50
49
  end
51
50
  end
52
51
 
53
52
  blocks
54
53
  end
55
54
 
56
- def create_style_block(selector_string, rule_set)
55
+ def create_style_block(selector_string, rule_set, media_types)
57
56
  specificity = CssParser.calculate_specificity(selector_string)
58
57
  selector = Selector.new(selector_string, specificity)
59
58
  properties = []
@@ -62,7 +61,7 @@ module Roadie
62
61
  properties << StyleProperty.new(prop, val, important, specificity)
63
62
  end
64
63
 
65
- StyleBlock.new(selector, properties)
64
+ StyleBlock.new(selector, properties, media_types)
66
65
  end
67
66
 
68
67
  def setup_parser(css)
@@ -1,3 +1,3 @@
1
1
  module Roadie
2
- VERSION = '3.3.0'
2
+ VERSION = '3.4.0'
3
3
  end
@@ -299,6 +299,152 @@ describe "Roadie functionality" do
299
299
  expect(result).to include("<td>One</td><td>1</td>")
300
300
  expect(result).to include("<td>Two</td><td>2</td>")
301
301
  end
302
+
303
+ it "doesn't inline styles in media queries with features" do
304
+ document = Roadie::Document.new <<-HTML
305
+ <html>
306
+ <head>
307
+ <link rel="stylesheet" href="/style.css">
308
+ </head>
309
+ <body>
310
+ <div class="colorful"></div>
311
+ </body>
312
+ </html>
313
+ HTML
314
+
315
+ document.asset_providers = TestProvider.new(
316
+ "/style.css" => <<-CSS
317
+ .colorful { color: green; }
318
+ @media screen and (max-width 600px) {
319
+ .colorful { color: red; }
320
+ }
321
+ CSS
322
+ )
323
+
324
+ result = parse_html document.transform
325
+ expect(result).to have_styling('color' => 'green').at_selector('.colorful')
326
+ end
327
+
328
+ it 'puts non-inlineable media queries in the head' do
329
+ document = Roadie::Document.new <<-HTML
330
+ <html>
331
+ <head>
332
+ <link rel="stylesheet" href="/style.css">
333
+ </head>
334
+ <body>
335
+ <div class="colorful"></div>
336
+ </body>
337
+ </html>
338
+ HTML
339
+
340
+ document.asset_providers = TestProvider.new(
341
+ "/style.css" => <<-CSS
342
+ .colorful { color: green; }
343
+ @media screen and (max-width 800px) {
344
+ .colorful { color: blue; }
345
+ }
346
+ @media screen, print and (max-width 800px) {
347
+ .colorful { color: blue; }
348
+ }
349
+ CSS
350
+ )
351
+
352
+ result = parse_html document.transform
353
+
354
+ styles = result.at_css('html > head > style').text
355
+ expected_result = <<-CSS
356
+ @media screen and (max-width 800px) { .colorful{color:blue} }
357
+ @media screen, print and (max-width 800px) { .colorful{color:blue} }
358
+ CSS
359
+ expected_result = expected_result.gsub(/[\s]+/, ' ').strip
360
+ actual_result = styles.gsub(/[\s]+/, ' ').strip
361
+
362
+ expect(actual_result).to eq(expected_result)
363
+ end
364
+
365
+ it 'groups non-inlineable media queries in the head by default' do
366
+ document = Roadie::Document.new <<-HTML
367
+ <html>
368
+ <head>
369
+ <link rel="stylesheet" href="/style.css">
370
+ </head>
371
+ <body>
372
+ <div class="colorful"></div>
373
+ </body>
374
+ </html>
375
+ HTML
376
+
377
+ document.asset_providers = TestProvider.new(
378
+ "/style.css" => <<-CSS
379
+ .colorful { color: green; }
380
+ @media screen and (max-width 600px) {
381
+ .colorful { color: red; width: 600px; }
382
+ }
383
+ @media screen and (max-width 600px) {
384
+ .colorful-2 { color: red; width: 600px; }
385
+ }
386
+ CSS
387
+ )
388
+
389
+ result = parse_html document.transform
390
+
391
+ styles = result.at_css('html > head > style').text
392
+ expected_result = <<-CSS
393
+ @media screen and (max-width 600px) {
394
+ .colorful{color:red;width:600px}
395
+ .colorful-2{color:red;width:600px}
396
+ }
397
+ CSS
398
+ expected_result = expected_result.gsub(/[\s]+/, ' ').strip
399
+ actual_result = styles.gsub(/[\s]+/, ' ').strip
400
+
401
+ expect(actual_result).to eq(expected_result)
402
+ end
403
+
404
+ describe 'if merge_media_queries is set to false' do
405
+ it "doesn't group non-inlineable media queries in the head" do
406
+ document = Roadie::Document.new <<-HTML
407
+ <html>
408
+ <head>
409
+ <link rel="stylesheet" href="/style.css">
410
+ </head>
411
+ <body>
412
+ <div class="colorful"></div>
413
+ </body>
414
+ </html>
415
+ HTML
416
+
417
+ document.merge_media_queries = false
418
+
419
+ document.asset_providers = TestProvider.new(
420
+ "/style.css" => <<-CSS
421
+ .colorful { color: green; }
422
+ @media screen and (max-width 600px) {
423
+ .colorful { color: red; width: 600px; }
424
+ }
425
+ @media screen and (max-width 600px) {
426
+ .colorful-2 { color: red; width: 600px; }
427
+ }
428
+ CSS
429
+ )
430
+
431
+ result = parse_html document.transform
432
+
433
+ styles = result.at_css('html > head > style').text
434
+ expected_result = <<-CSS
435
+ @media screen and (max-width 600px) {
436
+ .colorful{color:red;width:600px}
437
+ }
438
+ @media screen and (max-width 600px) {
439
+ .colorful-2{color:red;width:600px}
440
+ }
441
+ CSS
442
+ expected_result = expected_result.gsub(/[\s]+/, ' ').strip
443
+ actual_result = styles.gsub(/[\s]+/, ' ').strip
444
+
445
+ expect(actual_result).to eq(expected_result)
446
+ end
447
+ end
302
448
  end
303
449
 
304
450
  describe "on partial documents" do
@@ -7,29 +7,40 @@ module Roadie
7
7
  properties = []
8
8
  selector = double "Selector"
9
9
 
10
- block = StyleBlock.new(selector, properties)
10
+ block = StyleBlock.new(selector, properties, [:all])
11
11
  expect(block.selector).to eq(selector)
12
12
  expect(block.properties).to eq(properties)
13
13
  end
14
14
 
15
15
  it "delegates #specificity to the selector" do
16
16
  selector = double "Selector", specificity: 45
17
- expect(StyleBlock.new(selector, []).specificity).to eq(45)
18
- end
19
-
20
- it "delegates #inlinable? to the selector" do
21
- selector = double "Selector", inlinable?: "maybe"
22
- expect(StyleBlock.new(selector, []).inlinable?).to eq("maybe")
17
+ expect(StyleBlock.new(selector, [], [:all]).specificity).to eq(45)
23
18
  end
24
19
 
25
20
  it "delegates #selector_string to selector#to_s" do
26
21
  selector = double "Selector", to_s: "yey"
27
- expect(StyleBlock.new(selector, []).selector_string).to eq("yey")
22
+ expect(StyleBlock.new(selector, [], [:all]).selector_string).to eq("yey")
28
23
  end
29
24
 
30
25
  it "has a string representation" do
31
26
  properties = [double(to_s: "bar"), double(to_s: "baz")]
32
- expect(StyleBlock.new(double(to_s: "foo"), properties).to_s).to eq("foo{bar;baz}")
27
+ expect(StyleBlock.new(double(to_s: "foo"), properties, [:all]).to_s).to eq("foo{bar;baz}")
28
+ end
29
+
30
+ describe "#inlinable" do
31
+ context "when no media include feature condition" do
32
+ it "delegates #inlinable? to the selector" do
33
+ selector = double "Selector", inlinable?: "maybe"
34
+ expect(StyleBlock.new(selector, [], [:all]).inlinable?).to eq("maybe")
35
+ end
36
+ end
37
+
38
+ context "when one of media queries includes feature condition" do
39
+ it "returns false" do
40
+ selector = double "Selector", inlinable?: "maybe"
41
+ expect(StyleBlock.new(selector, [], [:all, :'screen (min-width: 300px)']).inlinable?).to be(false)
42
+ end
43
+ end
33
44
  end
34
45
  end
35
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roadie
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Magnus Bergmark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-04 00:00:00.000000000 Z
11
+ date: 2018-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -96,11 +96,9 @@ files:
96
96
  - ".yardopts"
97
97
  - Changelog.md
98
98
  - Gemfile
99
- - Guardfile
100
99
  - LICENSE
101
100
  - README.md
102
101
  - Rakefile
103
- - autotest/discover.rb
104
102
  - lib/roadie.rb
105
103
  - lib/roadie/asset_provider.rb
106
104
  - lib/roadie/asset_scanner.rb
data/Guardfile DELETED
@@ -1,20 +0,0 @@
1
- rspec_options = {
2
- cmd: 'rspec -f documentation',
3
- failed_mode: :keep,
4
- all_after_pass: true,
5
- all_on_start: true,
6
- run_all: {cmd: 'rspec -f progress'}
7
- }
8
-
9
- guard 'rspec', rspec_options do
10
- watch(%r{^spec/.+_spec\.rb$})
11
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
- watch('lib/roadie.rb') { "spec" }
13
- watch('lib/roadie/errors.rb') { "spec" }
14
-
15
- watch(%r{lib/roadie/rspec/.*\.rb}) { "spec" }
16
-
17
- watch(%r{spec/support/.*\.rb}) { "spec" }
18
- watch('spec/spec_helper.rb') { "spec" }
19
- end
20
-
@@ -1 +0,0 @@
1
- Autotest.add_discovery { 'rspec2' }