css_inliner 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|