css_inliner 0.1.1 → 0.2.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.
- data/{README → README.rdoc} +0 -0
- data/bin/css-inliner +1 -2
- data/css_inliner.gemspec +4 -4
- data/lib/css_inliner/csspool.rb +58 -0
- data/lib/css_inliner/extractor.rb +37 -14
- data/lib/css_inliner/inliner.rb +16 -17
- data/lib/css_inliner/version.rb +1 -1
- data/lib/css_inliner.rb +3 -2
- data/test/fixtures/sample1/rdoc.css +4 -4
- data/test/test_css_inliner.rb +0 -2
- data/test/test_extractor.rb +14 -10
- metadata +45 -22
data/{README → README.rdoc}
RENAMED
File without changes
|
data/bin/css-inliner
CHANGED
@@ -6,6 +6,7 @@ opt = OptionParser.new
|
|
6
6
|
Version = CSSInliner::VERSION
|
7
7
|
options = {}
|
8
8
|
|
9
|
+
opt.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] htmlfile"
|
9
10
|
opt.on('-o', '--output=OUTPUTFILE', 'file name to output result HTML') {|v| options[:output] = v}
|
10
11
|
opt.on('-i [SUFFIX]', '--in-place', '--overwrite', 'inplace editing') do |v|
|
11
12
|
options[:'in-place'] = true
|
@@ -23,5 +24,3 @@ elsif options[:output]
|
|
23
24
|
else
|
24
25
|
$stdout.write processed
|
25
26
|
end
|
26
|
-
|
27
|
-
exit 0
|
data/css_inliner.gemspec
CHANGED
@@ -13,18 +13,18 @@ Gem::Specification.new do |s|
|
|
13
13
|
into style attibute of HTML elements
|
14
14
|
}
|
15
15
|
|
16
|
-
# s.rubyforge_project = "css_inliner"
|
17
|
-
|
18
16
|
s.files = `git ls-files`.split("\n")
|
19
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
19
|
s.require_paths = ["lib"]
|
22
20
|
|
23
21
|
s.add_runtime_dependency "nokogiri", '~> 1'
|
24
|
-
s.add_runtime_dependency "
|
25
|
-
s.add_runtime_dependency "
|
22
|
+
s.add_runtime_dependency "csspool", '~> 3'
|
23
|
+
s.add_runtime_dependency "bsearch"
|
26
24
|
|
27
25
|
s.add_development_dependency "test-unit", '~> 2'
|
28
26
|
s.add_development_dependency "cover_me", '~> 1'
|
29
27
|
s.add_development_dependency "yard"
|
28
|
+
s.add_development_dependency "pry"
|
29
|
+
s.add_development_dependency "pry-doc"
|
30
30
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'csspool'
|
2
|
+
|
3
|
+
module CSSPool
|
4
|
+
module CSS
|
5
|
+
class << self
|
6
|
+
# Update declarations in base with ones in other
|
7
|
+
# @param [Array<Declaration>] base updated array of declarations
|
8
|
+
# @param [Array<Declaration>] other array of declarations
|
9
|
+
# @return [Array<Declaration>] base itself
|
10
|
+
def update_declarations(base, other)
|
11
|
+
other.each do |other_decl|
|
12
|
+
base_decls = base.find_all {|base_decl| base_decl.property == other_decl.property}
|
13
|
+
if base_decls.empty?
|
14
|
+
base << other_decl
|
15
|
+
else
|
16
|
+
base_decl = base_decls.pop
|
17
|
+
base_decls.each do |decl|
|
18
|
+
base_decl.update decl
|
19
|
+
end
|
20
|
+
base_decl.update other_decl
|
21
|
+
end
|
22
|
+
end
|
23
|
+
base
|
24
|
+
end
|
25
|
+
|
26
|
+
# Merge declarations in each argument
|
27
|
+
# @param [Array<Declaration>] base Array of declarations
|
28
|
+
# @param [Array<Declaration>] other Array of declarations
|
29
|
+
# @return [Aarray<Declaration>] merged array of declarations
|
30
|
+
def merge_declarations(base, other)
|
31
|
+
update_declarations base.dup, other
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Declaration
|
36
|
+
# @param [Declaration] other
|
37
|
+
# @return [Declaration] self
|
38
|
+
def update(other)
|
39
|
+
raise ArgumentError('different property') unless property == other.property
|
40
|
+
self.expressions = other.expressions if !important? or other.important?
|
41
|
+
self
|
42
|
+
end
|
43
|
+
alias merge! update
|
44
|
+
|
45
|
+
# @param [Declaration] other
|
46
|
+
# @return [Declaration] merged declaration
|
47
|
+
def merge(other)
|
48
|
+
dup.update other
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module Visitors
|
54
|
+
class ToCSS
|
55
|
+
alias visit_CSSInliner_CSSDocument visit_CSSPool_CSS_Document
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,7 +1,35 @@
|
|
1
|
+
require 'English'
|
1
2
|
require 'open-uri'
|
2
|
-
require '
|
3
|
+
require 'bsearch'
|
4
|
+
require 'css_inliner/csspool'
|
3
5
|
|
4
6
|
module CSSInliner
|
7
|
+
class CSSDocument < CSSPool::CSS::Document
|
8
|
+
# @return [Array<CSSPool::Selector>] Array of selectors in specificity order
|
9
|
+
attr_reader :sorted_selectors
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@sorted_selectors = []
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CSSDocumentHandler < CSSPool::CSS::DocumentHandler
|
18
|
+
def start_document
|
19
|
+
@document = CSSDocument.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_selector selector_list
|
23
|
+
super
|
24
|
+
selector_list.each do |selector|
|
25
|
+
index = @document.sorted_selectors.bsearch_upper_boundary { |existing|
|
26
|
+
existing.specificity <=> selector.specificity
|
27
|
+
}
|
28
|
+
@document.sorted_selectors.insert index, selector
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
5
33
|
class Extractor
|
6
34
|
attr_reader :document
|
7
35
|
|
@@ -17,9 +45,11 @@ module CSSInliner
|
|
17
45
|
end
|
18
46
|
|
19
47
|
def extract_from_link(remove_link_element = true)
|
20
|
-
@document.css('link
|
48
|
+
@document.css('link').inject([]) do |sources, link|
|
49
|
+
next unless link['rel'] == 'stylesheet'
|
21
50
|
begin
|
22
|
-
|
51
|
+
# To do: detect file encoding before open it(read only @charset value)
|
52
|
+
open(File.join(basedir, link['href']), 'r:BOM|UTF-8') {|f| sources << f.read}
|
23
53
|
rescue Errno::ENOENT
|
24
54
|
warn File.join(basedir, link['href']) + ' not found'
|
25
55
|
end
|
@@ -37,17 +67,10 @@ module CSSInliner
|
|
37
67
|
end
|
38
68
|
|
39
69
|
def integrate(*sources)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
rule_sets = rule_sets.sort_by {|rs| [rs.specificity, i += 1]}
|
45
|
-
blank_rule_set = CssParser::RuleSet.new(nil, nil)
|
46
|
-
rule_sets.inject(Hash.new(blank_rule_set)) do |rules, rs|
|
47
|
-
sel = rs.selectors * ','
|
48
|
-
rules[sel] = CssParser.merge rules[sel], rs
|
49
|
-
rules
|
50
|
-
end
|
70
|
+
source = sources.collect {|src| src * $RS}.join($RS)
|
71
|
+
source = 'book {}' if source.empty?
|
72
|
+
handler = CSSDocumentHandler.new
|
73
|
+
CSSPool::SAC::Parser.new(handler).parse(source)
|
51
74
|
end
|
52
75
|
|
53
76
|
def basedir
|
data/lib/css_inliner/inliner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'nokogiri'
|
3
3
|
require 'css_inliner/extractor'
|
4
|
+
require 'css_inliner/csspool'
|
4
5
|
|
5
6
|
module CSSInliner
|
6
7
|
class Inliner
|
@@ -13,29 +14,27 @@ module CSSInliner
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def inline
|
16
|
-
|
17
|
-
@document.
|
18
|
-
|
17
|
+
original_styles = {}
|
18
|
+
@document.search('.//*[@style]').each do |elem|
|
19
|
+
original_styles[elem] = elem['style']
|
20
|
+
elem.remove_attribute('style')
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
+
css = @extractor.extract
|
24
|
+
css.sorted_selectors.each do |selector|
|
25
|
+
sel = selector.to_s
|
23
26
|
next if sel =~ /@|:/
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
sel = 'body' if sel == '*' or sel == 'html'
|
28
|
+
@document.css(sel).each do |elem|
|
29
|
+
base = CSSPool.CSS("* {#{elem['style']}}").rule_sets.first.declarations
|
30
|
+
elem['style'] = CSSPool::CSS.update_declarations(base, selector.declarations).join
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
styles.each_pair do |elem, rule_set|
|
38
|
-
elem['style'] = rule_set.declarations_to_s
|
34
|
+
original_styles.each_pair do |elem, style|
|
35
|
+
base = CSSPool.CSS("* {#{elem['style']}}").rule_sets.first.declarations
|
36
|
+
orig = CSSPool.CSS("* {#{style}}").rule_sets.first.declarations
|
37
|
+
elem['style'] = CSSPool::CSS.update_declarations(base, orig).join
|
39
38
|
end
|
40
39
|
|
41
40
|
@document
|
data/lib/css_inliner/version.rb
CHANGED
data/lib/css_inliner.rb
CHANGED
@@ -2,6 +2,7 @@ require 'open-uri'
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'nokogiri'
|
4
4
|
require 'css_inliner/version'
|
5
|
+
require 'css_inliner/csspool'
|
5
6
|
require 'css_inliner/inliner'
|
6
7
|
|
7
8
|
module CSSInliner
|
@@ -12,8 +13,8 @@ module CSSInliner
|
|
12
13
|
# Returns whole document when nil
|
13
14
|
# @return [String] HTML source
|
14
15
|
def process(html, basedir = '.', element = nil)
|
15
|
-
doc = html.instance_of?
|
16
|
-
doc = Inliner.new(
|
16
|
+
doc = html.instance_of?(Nokogiri::XML::Document) ? html : Nokogiri.XML(html)
|
17
|
+
doc = Inliner.new(doc, basedir).inline
|
17
18
|
doc = doc.css(element)[0] if element
|
18
19
|
doc.to_s
|
19
20
|
end
|
@@ -615,7 +615,7 @@ div.method-source-code pre {
|
|
615
615
|
|
616
616
|
* html #TB_overlay { /* ie6 hack */
|
617
617
|
position: absolute;
|
618
|
-
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
|
618
|
+
/* height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); */
|
619
619
|
}
|
620
620
|
|
621
621
|
#TB_window {
|
@@ -632,7 +632,7 @@ div.method-source-code pre {
|
|
632
632
|
|
633
633
|
* html #TB_window { /* ie6 hack */
|
634
634
|
position: absolute;
|
635
|
-
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
|
635
|
+
/* margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); */
|
636
636
|
}
|
637
637
|
|
638
638
|
#TB_window img#TB_Image {
|
@@ -710,7 +710,7 @@ div.method-source-code pre {
|
|
710
710
|
|
711
711
|
* html #TB_load { /* ie6 hack */
|
712
712
|
position: absolute;
|
713
|
-
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
|
713
|
+
/* margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); */
|
714
714
|
}
|
715
715
|
|
716
716
|
#TB_HideSelect{
|
@@ -729,7 +729,7 @@ div.method-source-code pre {
|
|
729
729
|
|
730
730
|
* html #TB_HideSelect { /* ie6 hack */
|
731
731
|
position: absolute;
|
732
|
-
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
|
732
|
+
/* height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); */
|
733
733
|
}
|
734
734
|
|
735
735
|
#TB_iframeContent{
|
data/test/test_css_inliner.rb
CHANGED
data/test/test_extractor.rb
CHANGED
@@ -33,10 +33,8 @@ class TestExtractor < CSSInlinerTestCase
|
|
33
33
|
color: gray ;
|
34
34
|
}
|
35
35
|
'
|
36
|
-
expected =
|
37
|
-
|
38
|
-
actual = CssParser::Parser.new
|
39
|
-
actual.add_block! @extractor3.extract_from_style[0]
|
36
|
+
expected = CSSPool.CSS src
|
37
|
+
actual = CSSPool.CSS @extractor3.extract_from_style[0]
|
40
38
|
|
41
39
|
assert_equal expected.to_s, actual.to_s
|
42
40
|
end
|
@@ -69,11 +67,17 @@ a {
|
|
69
67
|
}
|
70
68
|
'
|
71
69
|
]
|
72
|
-
expected =
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
70
|
+
expected = <<EOC
|
71
|
+
h2 {
|
72
|
+
color: gray;
|
73
|
+
}
|
74
|
+
h2 p {
|
75
|
+
color: blue;
|
76
|
+
}
|
77
|
+
a {
|
78
|
+
text-decoration: none;
|
79
|
+
}
|
80
|
+
EOC
|
81
|
+
assert_equal expected.chomp, @extractor1.integrate(sources).to_css.chomp
|
78
82
|
end
|
79
83
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: css_inliner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-29 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement: &
|
16
|
+
requirement: &12417000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,32 +21,32 @@ dependencies:
|
|
21
21
|
version: '1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12417000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement: &
|
26
|
+
name: csspool
|
27
|
+
requirement: &12415820 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '3'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12415820
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement: &
|
37
|
+
name: bsearch
|
38
|
+
requirement: &12415220 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ! '>='
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
43
|
+
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *12415220
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: test-unit
|
49
|
-
requirement: &
|
49
|
+
requirement: &12414040 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '2'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *12414040
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: cover_me
|
60
|
-
requirement: &
|
60
|
+
requirement: &12430900 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,32 @@ dependencies:
|
|
65
65
|
version: '1'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *12430900
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: yard
|
71
|
-
requirement: &
|
71
|
+
requirement: &12430380 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *12430380
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: pry
|
82
|
+
requirement: &12429780 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *12429780
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: pry-doc
|
93
|
+
requirement: &12429300 !ruby/object:Gem::Requirement
|
72
94
|
none: false
|
73
95
|
requirements:
|
74
96
|
- - ! '>='
|
@@ -76,7 +98,7 @@ dependencies:
|
|
76
98
|
version: '0'
|
77
99
|
type: :development
|
78
100
|
prerelease: false
|
79
|
-
version_requirements: *
|
101
|
+
version_requirements: *12429300
|
80
102
|
description: ! "\n inline CSS from external file(s) and/or style elment(s) in head
|
81
103
|
element\n into style attibute of HTML elements\n "
|
82
104
|
email:
|
@@ -91,12 +113,13 @@ files:
|
|
91
113
|
- .gitignore
|
92
114
|
- Gemfile
|
93
115
|
- LICENSE
|
94
|
-
- README
|
116
|
+
- README.rdoc
|
95
117
|
- Rakefile
|
96
118
|
- bin/css-inliner
|
97
119
|
- bin/css-inliner-multifile
|
98
120
|
- css_inliner.gemspec
|
99
121
|
- lib/css_inliner.rb
|
122
|
+
- lib/css_inliner/csspool.rb
|
100
123
|
- lib/css_inliner/extractor.rb
|
101
124
|
- lib/css_inliner/inliner.rb
|
102
125
|
- lib/css_inliner/version.rb
|
@@ -244,7 +267,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
244
267
|
version: '0'
|
245
268
|
segments:
|
246
269
|
- 0
|
247
|
-
hash:
|
270
|
+
hash: -1019368120188778628
|
248
271
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
249
272
|
none: false
|
250
273
|
requirements:
|
@@ -253,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
276
|
version: '0'
|
254
277
|
segments:
|
255
278
|
- 0
|
256
|
-
hash:
|
279
|
+
hash: -1019368120188778628
|
257
280
|
requirements: []
|
258
281
|
rubyforge_project:
|
259
282
|
rubygems_version: 1.8.8
|