stylesheet 0.1.0 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d8731f136d13c2aafa5686bc348ed721890e8d8186ccf7b3d07b04b5e4b1d286
4
+ data.tar.gz: 5e1a9e9c982d43c12c2e7bed8c43703b7fae491282d1c17e24f25567bbbec08a
5
+ SHA512:
6
+ metadata.gz: 73c42acfa16d26fe5c48dffaaf738cf21452dcdc8e1c2be9ae050663a70be53eaab99a87cb9cce8f7096b04bd52b828e0704f15b70ec74cb0edf93323bc4bc42
7
+ data.tar.gz: 696f793a09c89575152c2a31730909e76d0328bb095c540c7c405347b6bc53f3e414619e86e956bee3e51d3a10f7ce47c4bfbcc34be627f2d6f3fb8b8354e8f5
data/README.md CHANGED
@@ -8,51 +8,65 @@ Get styles from a document:
8
8
 
9
9
  ```ruby
10
10
  document = Stylesheet::Document.new("http://sportspyder.com")
11
+ => #<Document location:http://sportspyder.com/>
12
+
11
13
  document.style_sheets
14
+ => [#<Stylesheet::CssStyleSheet:0x007fa905c58c20>,
15
+ #<Stylesheet::CssStyleSheet:0x007fa905c5f430>,
16
+ #<Stylesheet::CssStyleSheet:0x007fa905c5e968>]
12
17
  ```
13
18
 
14
19
  Get attributes of a stylesheet:
15
20
 
16
21
  ```ruby
17
22
  sheet = document.style_sheets[0]
18
- puts sheet.href
19
- puts sheet.type
23
+ => #<Stylesheet::CssStyleSheet:0x007fa905c58c20>
24
+
25
+ sheet.href
26
+ => "http://sportspyder.com/assets/application-26ff2c8d54ab9cd8e74af60fc650390e.css"
27
+
28
+ sheet.type
29
+ => "text/css"
20
30
  ```
21
31
 
22
32
  Get stylesheet media definitions:
23
33
 
24
34
  ```ruby
25
- sheet = document.style_sheets[0]
26
- sheet.media.each do |media|
27
- puts media
28
- end
35
+ sheet.media.map {|medium| medium }
36
+ => ["screen"]
29
37
  ```
30
38
 
31
39
  Get rules defined in a stylesheet:
32
40
 
33
41
  ```ruby
34
42
  sheet = Stylesheet::CssStyleSheet.new("http://sportspyder.com/stylesheets/screen.css")
35
- sheet.css_rules.each do |rule|
36
- puts rule.css_text
37
- puts rule.selector_text
38
- end
43
+ => #<Stylesheet::CssStyleSheet:0x007fa905c58c20>
44
+
45
+ rule = sheet.css_rules[0]
46
+ => #<Stylesheet::CssStyleRule>
47
+
48
+ rule.css_text
49
+ => "iframe.editor{width:580px;height:150px;border:1px solid #ccc;background-color:#fff}"
50
+
51
+ rule.selector_text
52
+ => "iframe.editor"
39
53
  ```
40
54
 
41
55
  Get declarations defined in a style rules:
42
56
 
43
57
  ```ruby
44
- sheet = document.style_sheets[0]
45
- rule = sheet.css_rules[0]
46
- puts rule.style[0]
47
- puts rule.style.border
58
+ rule.style[0]
59
+ => "width:580px"
60
+
61
+ rule.style.border
62
+ => "1px solid #ccc"
48
63
  ```
49
64
 
50
65
  ## Installation
51
66
 
52
- ```
53
- gem install stylesheet
54
- ```
55
- ```
67
+ To install Stylesheet, add the gem to your Gemfile:
68
+
69
+ ```ruby
56
70
  gem "stylesheet"
57
71
  ```
58
72
 
@@ -21,6 +21,7 @@ require 'stylesheet/css_charset_rule'
21
21
  require 'stylesheet/css_import_rule'
22
22
  require 'stylesheet/css_media_rule'
23
23
  require 'stylesheet/css_font_face_rule'
24
+ require 'stylesheet/css_null_rule'
24
25
 
25
26
  require 'stylesheet/css_style_declaration'
26
27
 
@@ -12,7 +12,9 @@ module Stylesheet
12
12
  end
13
13
 
14
14
  def style_sheet
15
- @style_sheet ||= CssStyleSheet.new(location.href)
15
+ @style_sheet ||= CssStyleSheet.new(:href => location.href,
16
+ :owner_rule => self,
17
+ :parent => parent_style_sheet)
16
18
  end
17
19
 
18
20
  def self.matches_rule?(text)
@@ -0,0 +1,16 @@
1
+ module Stylesheet
2
+ class CssNullRule < CssRule
3
+
4
+ def type
5
+ CssRule::NULL_RULE
6
+ end
7
+
8
+ def self.matches_rule?(text)
9
+ true
10
+ end
11
+
12
+ private
13
+
14
+ def parse_css_text; end
15
+ end
16
+ end
@@ -1,5 +1,6 @@
1
1
  module Stylesheet
2
2
  class CssRule
3
+ NULL_RULE = 0
3
4
  STYLE_RULE = 1
4
5
  CHARSET_RULE = 2
5
6
  IMPORT_RULE = 3
@@ -50,7 +51,7 @@ module Stylesheet
50
51
 
51
52
  private
52
53
 
53
- def parse_css_text(css_text)
54
+ def parse_css_text
54
55
  raise NotImplementedError
55
56
  end
56
57
  end
@@ -1,7 +1,7 @@
1
1
  module Stylesheet
2
2
  class CssRuleList
3
3
  extend Forwardable
4
- def_delegators :@rules, :length, :size, :[], :each, :to_s
4
+ def_delegators :@rules, :length, :size, :[], :each, :insert, :delete_at, :to_s
5
5
  include Enumerable
6
6
 
7
7
  def initialize(rules, parent = nil)
@@ -11,15 +11,18 @@ module Stylesheet
11
11
  def item(index)
12
12
  @rules[index]
13
13
  end
14
-
14
+
15
15
  private
16
16
 
17
17
  def parse(rules, parent)
18
+ # clean out comments
19
+ rules = rules.gsub(/\/\*[\s\S]*?\*\//, '').gsub("/*", "").gsub("*/", "")
20
+
18
21
  # clean extraneous whitespace
19
22
  rules = rules.to_s.gsub(/\s+/m, " ").gsub(/([\};])\s/, '\1')
20
23
 
21
24
  directive_re = "@.+?;"
22
- rules_re = ".+?\{.+?\}"
25
+ rules_re = ".+?\{.*?\}"
23
26
  split_rules = rules.scan(/(#{directive_re}|#{rules_re})/im).map {|r| r[0] }
24
27
 
25
28
  split_rules.map do |css_text|
@@ -1,35 +1,39 @@
1
1
  module Stylesheet
2
2
  class CssStyleDeclaration
3
3
  extend Forwardable
4
- def_delegators :@declarations, :length, :size, :[], :each, :<<, :push, :delete, :to_s
4
+ def_delegators :@declarations_list, :length, :size, :[], :each, :<<, :push, :delete, :to_s
5
5
  include Enumerable
6
6
 
7
- attr_reader :parent_rule
7
+ attr_reader :declarations, :parent_rule
8
8
 
9
9
  def initialize(options={})
10
+ @declarations = Hash.new("")
10
11
  @parent_rule = options[:parent_rule]
11
12
  self.css_text = options[:css_text]
12
13
  end
13
14
 
14
15
  def css_text=(css_text)
15
- @declarations, @rules = [], Hash.new("")
16
+ @declarations_list = []
17
+
18
+ re = /((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)\s*/
19
+ css_text.to_s.strip.chomp(";").scan(re).flatten.each do |declaration|
20
+ next unless declaration.include?(":")
16
21
 
17
- css_text.to_s.strip.chomp(";").split(";").each do |declaration|
18
22
  property, value = declaration.split(":", 2)
19
- @declarations << declaration.strip
20
- @rules[Inflector.camelize(property.strip)] = parse_value(value.strip)
23
+ @declarations_list << declaration.strip
24
+ @declarations[property.strip] = parse_value(value.strip)
21
25
  end
22
26
  end
23
27
 
24
28
  def css_text
25
- css_text = @declarations.join("; ")
29
+ css_text = @declarations_list.join("; ")
26
30
  css_text += ";" if css_text != ""
27
31
  end
28
32
 
29
33
  alias_method :to_s, :css_text
30
34
 
31
35
  def method_missing(name, *args)
32
- @rules[name.to_s]
36
+ @declarations[Inflector.dasherize(name.to_s)]
33
37
  end
34
38
 
35
39
  private
@@ -1,9 +1,9 @@
1
1
  module Stylesheet
2
2
  class CssStyleSheet
3
3
  attr_accessor :parent, :title
4
- attr_reader :href, :media
4
+ attr_reader :href, :media, :owner_rule
5
5
  attr_writer :disabled, :type
6
-
6
+
7
7
  def initialize(args)
8
8
  if args.kind_of?(String)
9
9
  init_with_url(args)
@@ -11,18 +11,19 @@ module Stylesheet
11
11
  init_with_hash(args)
12
12
  end
13
13
  end
14
-
14
+
15
15
  def init_with_url(url)
16
16
  self.href = url
17
17
  self.media = ""
18
18
  self.content = nil
19
19
  end
20
-
20
+
21
21
  def init_with_hash(args)
22
- @parent = args[:parent]
23
- @title = args[:title]
24
- @type = args[:type]
25
-
22
+ @parent = args[:parent]
23
+ @title = args[:title]
24
+ @type = args[:type]
25
+ @owner_rule = args[:owner_rule]
26
+
26
27
  self.href = args[:href]
27
28
  self.location = args[:location]
28
29
  self.media = args[:media]
@@ -32,25 +33,25 @@ module Stylesheet
32
33
  def disabled?
33
34
  @disabled || false
34
35
  end
35
-
36
+
36
37
  def type
37
38
  @type || "text/css"
38
39
  end
39
-
40
+
40
41
  def href=(url)
41
42
  return unless url
42
43
  @url = url
43
44
  @href = location.to_s
44
45
  end
45
-
46
+
46
47
  def media=(media)
47
48
  @media ||= MediaList.new(media)
48
49
  end
49
-
50
+
50
51
  def content=(content)
51
- @content = content if content != ""
52
+ @content = content if content
52
53
  end
53
-
54
+
54
55
  def content
55
56
  @content ||= request_content
56
57
  end
@@ -61,15 +62,31 @@ module Stylesheet
61
62
 
62
63
  alias_method :rules, :css_rules
63
64
 
64
- def parent_style_sheet
65
- parent
65
+ def import_rules
66
+ css_rules.select {|r| r.type == CssRule::IMPORT_RULE }
66
67
  end
67
68
 
69
+ def style_rules
70
+ css_rules.select {|r| r.type == CssRule::STYLE_RULE }
71
+ end
72
+
73
+ def parent_style_sheet
74
+ @parent if @owner_rule
75
+ end
76
+
77
+ def delete_rule(index)
78
+ @css_rules.delete_at(index)
79
+ end
80
+
81
+ def insert_rule(rule, index)
82
+ @css_rules.insert(index, rule)
83
+ end
84
+
68
85
  def location
69
86
  return if inline_css?
70
87
  @location ||= Location.new(@url, parent && parent.location)
71
88
  end
72
-
89
+
73
90
  def location=(location)
74
91
  return unless location
75
92
 
@@ -83,13 +100,13 @@ module Stylesheet
83
100
  def standalone_css?
84
101
  !parent
85
102
  end
86
-
103
+
87
104
  def inline_css?
88
105
  !@url || @url == ""
89
106
  end
90
107
 
91
108
  def request_content
92
- raise InvalidLocationError unless location.valid?
109
+ raise InvalidLocationError unless location && location.valid?
93
110
  request.get(location.href)
94
111
  end
95
112
 
@@ -97,4 +114,4 @@ module Stylesheet
97
114
  @request ||= Stylesheet.request
98
115
  end
99
116
  end
100
- end
117
+ end
@@ -47,7 +47,7 @@ module Stylesheet
47
47
  end
48
48
 
49
49
  def valid?
50
- valid_protocol? && valid_host?
50
+ !!(valid_protocol? && valid_host?)
51
51
  end
52
52
 
53
53
  def expand_paths_from_parent
@@ -74,19 +74,19 @@ module Stylesheet
74
74
  def valid_protocol?
75
75
  protocol && protocol != ":"
76
76
  end
77
-
77
+
78
78
  def valid_host?
79
79
  host && host != ""
80
80
  end
81
-
81
+
82
82
  def valid_port?
83
83
  port && port != ""
84
84
  end
85
-
85
+
86
86
  def standard_port?
87
87
  port_80? || port_443?
88
88
  end
89
-
89
+
90
90
  def port_80?
91
91
  uri && uri.port == 80 && uri.scheme == "http"
92
92
  end
@@ -100,14 +100,13 @@ module Stylesheet
100
100
  URI.parse(url.strip)
101
101
  rescue URI::InvalidURIError
102
102
  URI.parse(URI.escape(url.strip))
103
- end
103
+ end
104
104
 
105
105
  # re-raise external library errors in our namespace
106
106
  rescue URI::InvalidURIError => error
107
107
  raise Stylesheet::InvalidLocationError.new(
108
108
  "#{error.class}: #{error.message}")
109
109
  end
110
-
110
+
111
111
  end
112
112
  end
113
-
@@ -8,12 +8,12 @@ module Stylesheet
8
8
 
9
9
  curl.body_str
10
10
 
11
- rescue Stylsheet::Error
11
+ rescue Stylesheet::Error
12
12
  raise
13
13
 
14
14
  # re-raise external library errors in our namespace
15
15
  rescue => error
16
- raise Stylsheet::Error.new("#{error.class}: #{error.message}")
16
+ raise Stylesheet::Error.new("#{error.class}: #{error.message}")
17
17
  end
18
18
 
19
19
  def user_agent
@@ -1,3 +1,3 @@
1
1
  module Stylesheet
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -23,17 +23,17 @@ describe CssCharsetRule do
23
23
  describe ".matches_rule?" do
24
24
  it "should match text starting with @charset" do
25
25
  matches = CssCharsetRule.matches_rule?(css_text)
26
- expect(matches).to be_true
26
+ expect(matches).to eq true
27
27
  end
28
28
 
29
29
  it "should not match text without at-rule" do
30
30
  matches = CssCharsetRule.matches_rule?("a:link { color: #357ad1; }")
31
- expect(matches).to be_false
31
+ expect(matches).to eq false
32
32
  end
33
33
 
34
34
  it "should not match text without charset" do
35
35
  matches = CssCharsetRule.matches_rule?("@import url(\"import1.css\");")
36
- expect(matches).to be_false
36
+ expect(matches).to eq false
37
37
  end
38
38
  end
39
- end
39
+ end
@@ -31,17 +31,17 @@ describe CssFontFaceRule do
31
31
  describe ".matches_rule?" do
32
32
  it "should match text starting with @font-face" do
33
33
  matches = CssFontFaceRule.matches_rule?(css_text)
34
- expect(matches).to be_true
34
+ expect(matches).to eq true
35
35
  end
36
36
 
37
37
  it "should not match text without at-rule" do
38
38
  matches = CssFontFaceRule.matches_rule?("a:link { color: #357ad1; }")
39
- expect(matches).to be_false
39
+ expect(matches).to eq false
40
40
  end
41
41
 
42
42
  it "should not match text without font-face" do
43
43
  matches = CssFontFaceRule.matches_rule?("@import url(\"import1.css\");")
44
- expect(matches).to be_false
44
+ expect(matches).to eq false
45
45
  end
46
46
  end
47
- end
47
+ end
@@ -21,9 +21,9 @@ describe CssImportRule do
21
21
  let(:parent) do
22
22
  CssStyleSheet.new("http://example.com/css_import/stylesheets/screen.css")
23
23
  end
24
-
24
+
25
25
  let(:rule_url) { "http://example.com/css_import/stylesheets/import1.css" }
26
-
26
+
27
27
  it "parses an url from the style rule" do
28
28
  css_text = "@import url(\"http://example.com/css_import/stylesheets/import1.css\");"
29
29
 
@@ -162,17 +162,17 @@ describe CssImportRule do
162
162
  describe ".matches_rule?" do
163
163
  it "should match text starting with @import" do
164
164
  matches = CssImportRule.matches_rule?(css_text)
165
- expect(matches).to be_true
165
+ expect(matches).to eq true
166
166
  end
167
167
 
168
168
  it "should not match text without at-rule" do
169
169
  matches = CssImportRule.matches_rule?("a:link { color: #357ad1; }")
170
- expect(matches).to be_false
170
+ expect(matches).to eq false
171
171
  end
172
172
 
173
173
  it "should not match text without import" do
174
174
  matches = CssImportRule.matches_rule?("@charset \"UTF-8\";")
175
- expect(matches).to be_false
175
+ expect(matches).to eq false
176
176
  end
177
177
  end
178
- end
178
+ end
@@ -41,17 +41,17 @@ describe CssMediaRule do
41
41
  describe ".matches_rule?" do
42
42
  it "should match text starting with @media" do
43
43
  matches = CssMediaRule.matches_rule?(css_text)
44
- expect(matches).to be_true
44
+ expect(matches).to eq true
45
45
  end
46
46
 
47
47
  it "should not match text without at-rule" do
48
48
  matches = CssMediaRule.matches_rule?("a:link { color: #357ad1; }")
49
- expect(matches).to be_false
49
+ expect(matches).to eq false
50
50
  end
51
51
 
52
52
  it "should not match text without media" do
53
53
  matches = CssMediaRule.matches_rule?("@charset \"UTF-8\";")
54
- expect(matches).to be_false
54
+ expect(matches).to eq false
55
55
  end
56
56
  end
57
- end
57
+ end
@@ -23,7 +23,34 @@ describe CssRuleList do
23
23
  src: url(\"http://example.com/fonts/VeraSeBd.ttf\");
24
24
  }"
25
25
  end
26
+
27
+ let(:style_w_comments) do
28
+ "body {
29
+ color: #444;
30
+ background-color: #535353;
31
+ }
32
+
33
+ /* style paragraphs */
34
+ p {
35
+ font-size: 90%;
36
+ }"
37
+ end
38
+
39
+ let(:style_w_mismatched_comments) do
40
+ "body {
41
+ color: #444;
42
+ background-color: #535353;
43
+ }
44
+
45
+ */
46
+ p {
47
+ font-size: 90%;
48
+ }" end
26
49
 
50
+ let(:style_w_empty_rules) do
51
+ "#cboxOverlay{color:#ccc}#colorbox{}#cboxTopLeft{width:21px;}"
52
+ end
53
+
27
54
  describe ".new" do
28
55
  it "parses charset rules" do
29
56
  rules = CssRuleList.new(styles)
@@ -49,6 +76,28 @@ describe CssRuleList do
49
76
  rules = CssRuleList.new(styles)
50
77
  expect(rules[4]).to be_kind_of(CssFontFaceRule)
51
78
  end
79
+
80
+ it "removes comments" do
81
+ rules = CssRuleList.new(style_w_comments)
82
+ expect(rules.length).to eq 2
83
+ expect(rules[0].css_text).to eq "body { color: #444;background-color: #535353;}"
84
+ expect(rules[1].css_text).to eq "p { font-size: 90%;}"
85
+ end
86
+
87
+ it "removes mismatched comments" do
88
+ rules = CssRuleList.new(style_w_mismatched_comments)
89
+ expect(rules.length).to eq 2
90
+ expect(rules[0].css_text).to eq "body { color: #444;background-color: #535353;}"
91
+ expect(rules[1].css_text).to eq "p { font-size: 90%;}"
92
+ end
93
+
94
+ it "parses empty rules" do
95
+ rules = CssRuleList.new(style_w_empty_rules)
96
+ expect(rules.length).to eq 3
97
+ expect(rules[0].css_text).to eq "#cboxOverlay{color:#ccc}"
98
+ expect(rules[1].css_text).to eq "#colorbox{}"
99
+ expect(rules[2].css_text).to eq "#cboxTopLeft{width:21px;}"
100
+ end
52
101
  end
53
102
 
54
103
  describe "#[]" do
@@ -26,6 +26,15 @@ describe CssRule do
26
26
  src: url(\"http://example.com/fonts/VeraSeBd.ttf\");
27
27
  }"
28
28
  end
29
+
30
+ let(:moz_doc_text) do
31
+ "@-moz-document url-prefix() {
32
+ .rec_details .rec-ellipsis:before {
33
+ float:right;
34
+ content: url(/fade.png);
35
+ }
36
+ }"
37
+ end
29
38
 
30
39
  describe ".factory" do
31
40
  it "should build an a css style rule" do
@@ -58,6 +67,12 @@ describe CssRule do
58
67
  :parent_style_sheet => Object.new)
59
68
  expect(rule).to be_kind_of(CssFontFaceRule)
60
69
  end
70
+
71
+ it "should build a null rule" do
72
+ rule = CssRule.factory(:css_text => moz_doc_text,
73
+ :parent_style_sheet => Object.new)
74
+ expect(rule).to be_kind_of(CssNullRule)
75
+ end
61
76
  end
62
77
 
63
78
  describe "#css_text" do
@@ -51,6 +51,17 @@ describe CssStyleDeclaration do
51
51
  end
52
52
  end
53
53
 
54
+ describe "rules" do
55
+ it "returns a hash of rules" do
56
+ expected = {"color" => "#444",
57
+ "font-size" => "12px",
58
+ "font-family" => "Arial, Verdana",
59
+ "border-left" => "1px solid red",
60
+ "border-right-width" => "1px",
61
+ "background-color" => "#535353"}
62
+ expect(declaration.declarations).to eq expected
63
+ end
64
+ end
54
65
 
55
66
  describe "#parent_rule" do
56
67
  it "returns the parent css style rule" do
@@ -68,4 +79,33 @@ describe CssStyleDeclaration do
68
79
  expect(declaration.overflow).to eq ""
69
80
  end
70
81
  end
82
+
83
+ describe "a declaration with base64 encoded rule" do
84
+ let(:css_text) do
85
+ "background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIi);color:#1d6299;"
86
+ end
87
+
88
+ it "returns the css style declaration for rules with base64 data" do
89
+ rule = CssStyleRule.new(:css_text => "div.section { #{css_text} }")
90
+ decl = CssStyleDeclaration.new(:css_text => css_text, :parent_rule => rule)
91
+
92
+ expected = {"background" => "url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIi)",
93
+ "color" => "#1d6299"}
94
+ expect(decl.declarations).to eq expected
95
+ end
96
+ end
97
+
98
+ describe "a declaration with an invalid rule" do
99
+ let(:css_text) do
100
+ "padding0;color:#1d6299;"
101
+ end
102
+
103
+ it "skips the invalid rule" do
104
+ rule = CssStyleRule.new(:css_text => "div.section { #{css_text} }")
105
+ decl = CssStyleDeclaration.new(:css_text => css_text, :parent_rule => rule)
106
+
107
+ expected = {"color" => "#1d6299"}
108
+ expect(decl.declarations).to eq expected
109
+ end
110
+ end
71
111
  end
@@ -42,12 +42,12 @@ describe CssStyleRule do
42
42
  describe ".matches_rule?" do
43
43
  it "should match text that doesn't begin with an at-rule" do
44
44
  matches = CssStyleRule.matches_rule?(css_text)
45
- expect(matches).to be_true
45
+ expect(matches).to eq true
46
46
  end
47
47
 
48
48
  it "should not match rules starting with at-rule" do
49
49
  matches = CssStyleRule.matches_rule?("@import url(\"import1.css\");")
50
- expect(matches).to be_false
50
+ expect(matches).to eq false
51
51
  end
52
52
  end
53
- end
53
+ end
@@ -8,10 +8,10 @@ describe CssStyleSheet do
8
8
  describe "#disabled" do
9
9
  it "shows if style sheet is disabled" do
10
10
  sheet = CssStyleSheet.new("http://example.com/css/stylesheets/screen.css")
11
- expect(sheet.disabled?).to be_false
11
+ expect(sheet.disabled?).to eq false
12
12
 
13
13
  sheet.disabled = true
14
- expect(sheet.disabled?).to be_true
14
+ expect(sheet.disabled?).to eq true
15
15
  end
16
16
  end
17
17
 
@@ -90,15 +90,20 @@ describe CssStyleSheet do
90
90
  end
91
91
  end
92
92
 
93
- describe "#owner_node" do
94
- it "references owning node" do
93
+ describe "#parent_style_sheet" do
94
+ let(:parent) do
95
+ CssStyleSheet.new("http://example.com/css_import/stylesheets/screen.css")
96
+ end
95
97
 
98
+ it "should be nil for non-imported sheets" do
99
+ expect(parent.parent_style_sheet).to be_nil
96
100
  end
97
- end
98
-
99
- describe "#parent_style_sheet" do
101
+
100
102
  it "references parent style sheet" do
103
+ text = "@import url(\"import1.css\");"
104
+ rule = CssImportRule.new(:css_text => text, :parent_style_sheet => parent)
101
105
 
106
+ expect(rule.style_sheet.parent_style_sheet).to eq parent
102
107
  end
103
108
  end
104
109
 
@@ -122,7 +127,18 @@ describe CssStyleSheet do
122
127
  expect(sheet.type).to eq "text/css"
123
128
  end
124
129
  end
125
-
130
+
131
+ describe "#content" do
132
+ it "doesn't fetch for empty inline styles" do
133
+ sheet = CssStyleSheet.new(content: "")
134
+
135
+ expect {
136
+ sheet.css_rules.map {|r| r.content }
137
+ }.not_to raise_error
138
+ end
139
+
140
+ end
141
+
126
142
  describe "#css_rules" do
127
143
  it "returns a list of css rules found in the style sheet" do
128
144
  sheet = CssStyleSheet.new("http://example.com/css/stylesheets/screen.css")
@@ -137,21 +153,69 @@ describe CssStyleSheet do
137
153
  end
138
154
  end
139
155
 
156
+ describe "#import_rules" do
157
+ it "returns all import rules from style sheet" do
158
+ sheet = CssStyleSheet.new("http://example.com/css_import/stylesheets/screen.css")
159
+ expect(sheet.import_rules.length).to eq 9
160
+
161
+ sheet.import_rules.each do |rule|
162
+ expect(rule.type).to eq CssRule::IMPORT_RULE
163
+ end
164
+ end
165
+ end
166
+
167
+ describe "#style_rules" do
168
+ it "returns all style rules from style sheet" do
169
+ sheet = CssStyleSheet.new("http://example.com/css_import/stylesheets/screen.css")
170
+ expect(sheet.style_rules.length).to eq 1
171
+
172
+ sheet.style_rules.each do |rule|
173
+ expect(rule.type).to eq CssRule::STYLE_RULE
174
+ end
175
+ end
176
+ end
177
+
140
178
  describe "#owner_rule" do
179
+ let(:parent) do
180
+ CssStyleSheet.new("http://example.com/css_import/stylesheets/screen.css")
181
+ end
182
+
183
+ it "should be nil for non-imported sheets" do
184
+ expect(parent.owner_rule).to be_nil
185
+ end
186
+
141
187
  it "references the owner rule" do
188
+ text = "@import url(\"import1.css\");"
189
+ rule = CssImportRule.new(:css_text => text, :parent_style_sheet => parent)
142
190
 
191
+ expect(rule.style_sheet.owner_rule).to eq rule
143
192
  end
144
193
  end
145
194
 
146
195
  describe "#delete_rule" do
147
196
  it "deletes a rule from the css rules" do
197
+ css = "div {\n background-color: #aaa;\n} span {\n color: #444; \n}"
198
+ sheet = CssStyleSheet.new(:content => css)
148
199
 
200
+ sheet.css_rules
201
+ expect(sheet.css_rules.length).to eq 2
202
+
203
+ sheet.delete_rule(0)
204
+ expect(sheet.css_rules.length).to eq 1
205
+ expect(sheet.css_rules[0].css_text).to eq "span { color: #444;}"
149
206
  end
150
207
  end
151
208
 
152
209
  describe "#insert_rule" do
153
210
  it "adds a rule to the css rules" do
211
+ css = "div {\n background-color: #aaa;\n} span {\n color: #444; \n}"
212
+ sheet = CssStyleSheet.new(:content => css)
213
+
214
+ expect(sheet.css_rules.length).to eq 2
154
215
 
216
+ sheet.insert_rule("#blanc { color: white }", 0);
217
+ expect(sheet.css_rules.length).to eq 3
218
+
155
219
  end
156
220
  end
157
- end
221
+ end
@@ -8,18 +8,14 @@ describe Location do
8
8
  location = Location.new(url)
9
9
  expect(location.host).to eq "initvisual.com"
10
10
  end
11
-
11
+
12
12
  it "should accept relative urls" do
13
13
  location = Location.new("/some/path.html")
14
14
  expect(location.to_s).to eq "/some/path.html"
15
15
  end
16
-
17
- it "should throw error for invalid host" do
18
- expect { Location.new("http://") }.to raise_error(InvalidLocationError)
19
- end
20
16
  end
21
-
22
-
17
+
18
+
23
19
  describe "#new with parent" do
24
20
  it "should not expand a full url" do
25
21
  parent = Location.new("http://example.com/css/url.html")
@@ -31,7 +27,7 @@ describe Location do
31
27
  it "should expand a relative path into a full path given the parent" do
32
28
  parent = Location.new("http://example.com/css/relative.html")
33
29
  location = Location.new("stylesheets/screen.css", parent)
34
-
30
+
35
31
  expect(location.to_s).to eq "http://example.com/css/stylesheets/screen.css"
36
32
  end
37
33
 
@@ -40,9 +36,9 @@ describe Location do
40
36
  location = Location.new("/css/stylesheets/screen.css", parent)
41
37
 
42
38
  expect(location.to_s).to eq "http://example.com/css/stylesheets/screen.css"
43
- end
39
+ end
44
40
  end
45
-
41
+
46
42
 
47
43
  describe "#host" do
48
44
  it "should parse out the url host" do
@@ -50,27 +46,27 @@ describe Location do
50
46
  expect(location.host).to eq "initvisual.com"
51
47
  end
52
48
  end
53
-
54
- describe "#host=" do
55
- it "should assign host to url" do
49
+
50
+ describe "#host=" do
51
+ it "should assign host to url" do
56
52
  location = Location.new(url)
57
-
53
+
58
54
  location.host = "derekdevries.com"
59
55
  expect(location.host).to eq "derekdevries.com"
60
56
  end
61
57
  end
62
-
58
+
63
59
  describe "#hostname" do
64
60
  it "should parse out the url hostname" do
65
61
  location = Location.new(url)
66
62
  expect(location.hostname).to eq "initvisual.com"
67
63
  end
68
64
  end
69
-
65
+
70
66
  describe "#hostname=" do
71
67
  it "should assign hostname to url" do
72
68
  location = Location.new(url)
73
-
69
+
74
70
  location.hostname = "derekdevries.com"
75
71
  expect(location.hostname).to eq "derekdevries.com"
76
72
  end
@@ -86,14 +82,14 @@ describe Location do
86
82
  describe "#pathname=" do
87
83
  it "should assign path to url" do
88
84
  location = Location.new(url)
89
-
85
+
90
86
  location.pathname = "/work"
91
87
  expect(location.pathname).to eq "/work"
92
88
  end
93
89
 
94
90
  it "add initial forward-slash if not given" do
95
91
  location = Location.new(url)
96
-
92
+
97
93
  location.pathname = "work"
98
94
  expect(location.pathname).to eq "/work"
99
95
  end
@@ -243,18 +239,23 @@ describe Location do
243
239
  describe "#valid?" do
244
240
  it "should be true with a valid host and protocol" do
245
241
  location = Location.new("http://initvisual.com")
246
- expect(location.valid?).to be_true
242
+ expect(location.valid?).to eq true
247
243
  end
248
244
 
249
- it "should be false for an invalid host" do
245
+ it "should be false for an invalid host" do
250
246
  location = Location.new("/asdf")
251
- expect(location.valid?).to be_false
247
+ expect(location.valid?).to eq false
248
+ end
249
+
250
+ it "should be false for a missing host" do
251
+ location = Location.new("http://")
252
+ expect(location.valid?).to eq false
252
253
  end
253
254
 
254
- it "should be false for an invalid protocol" do
255
+ it "should be false for an invalid protocol" do
255
256
  location = Location.new("foo.com/asdf")
256
- expect(location.valid?).to be_false
257
+ expect(location.valid?).to eq false
257
258
  end
258
259
  end
259
260
 
260
- end
261
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylesheet do
4
+ describe "#get" do
5
+ it "must return results" do
6
+ request = Request.new
7
+
8
+ # body = request.get("http://google.com")
9
+ # expect(body).to include "<html"
10
+ end
11
+ end
12
+ end
@@ -6,7 +6,7 @@ require 'stylesheet/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "stylesheet"
8
8
  gem.version = Stylesheet::VERSION
9
- gem.summary = %q{Stylesheet is a CSS style sheet parser}
9
+ gem.summary = %q{A CSS parser based on the DOM API}
10
10
  gem.description = gem.summary
11
11
 
12
12
  gem.required_ruby_version = '>= 1.9.3'
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
24
24
  gem.add_runtime_dependency("curb", "~> 0.8")
25
25
  gem.add_runtime_dependency("nokogiri", "~> 1.5")
26
26
 
27
+ gem.add_development_dependency("rake")
27
28
  gem.add_development_dependency("rspec", "~> 2.9")
28
29
  gem.add_development_dependency("cucumber", "~> 1.2")
29
30
 
metadata CHANGED
@@ -1,136 +1,135 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stylesheet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.1.6
6
5
  platform: ruby
7
6
  authors:
8
7
  - Derek DeVries
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
11
+ date: 2020-08-24 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: curb
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0.8'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0.8'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: nokogiri
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: '1.5'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
46
55
  - !ruby/object:Gem::Dependency
47
56
  name: rspec
48
57
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
58
  requirements:
51
- - - ~>
59
+ - - "~>"
52
60
  - !ruby/object:Gem::Version
53
61
  version: '2.9'
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
- - - ~>
66
+ - - "~>"
60
67
  - !ruby/object:Gem::Version
61
68
  version: '2.9'
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: cucumber
64
71
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
72
  requirements:
67
- - - ~>
73
+ - - "~>"
68
74
  - !ruby/object:Gem::Version
69
75
  version: '1.2'
70
76
  type: :development
71
77
  prerelease: false
72
78
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
79
  requirements:
75
- - - ~>
80
+ - - "~>"
76
81
  - !ruby/object:Gem::Version
77
82
  version: '1.2'
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: guard
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
- - - ~>
87
+ - - "~>"
84
88
  - !ruby/object:Gem::Version
85
89
  version: '1.7'
86
90
  type: :development
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
- - - ~>
94
+ - - "~>"
92
95
  - !ruby/object:Gem::Version
93
96
  version: '1.7'
94
97
  - !ruby/object:Gem::Dependency
95
98
  name: guard-rspec
96
99
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
100
  requirements:
99
- - - ~>
101
+ - - "~>"
100
102
  - !ruby/object:Gem::Version
101
103
  version: '2.5'
102
104
  type: :development
103
105
  prerelease: false
104
106
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
107
  requirements:
107
- - - ~>
108
+ - - "~>"
108
109
  - !ruby/object:Gem::Version
109
110
  version: '2.5'
110
111
  - !ruby/object:Gem::Dependency
111
112
  name: rb-fsevent
112
113
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
114
  requirements:
115
- - - ~>
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0.9'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
121
  requirements:
123
- - - ~>
122
+ - - "~>"
124
123
  - !ruby/object:Gem::Version
125
124
  version: '0.9'
126
- description: Stylesheet is a CSS style sheet parser
125
+ description: A CSS parser based on the DOM API
127
126
  email:
128
127
  - derek@sportspyder.com
129
128
  executables: []
130
129
  extensions: []
131
130
  extra_rdoc_files: []
132
131
  files:
133
- - .gitignore
132
+ - ".gitignore"
134
133
  - Gemfile
135
134
  - Guardfile
136
135
  - LICENSE.txt
@@ -148,6 +147,7 @@ files:
148
147
  - lib/stylesheet/css_font_face_rule.rb
149
148
  - lib/stylesheet/css_import_rule.rb
150
149
  - lib/stylesheet/css_media_rule.rb
150
+ - lib/stylesheet/css_null_rule.rb
151
151
  - lib/stylesheet/css_rule.rb
152
152
  - lib/stylesheet/css_rule_list.rb
153
153
  - lib/stylesheet/css_style_declaration.rb
@@ -205,6 +205,7 @@ files:
205
205
  - spec/inflector_spec.rb
206
206
  - spec/location_spec.rb
207
207
  - spec/media_list_spec.rb
208
+ - spec/request_spec.rb
208
209
  - spec/spec_helper.rb
209
210
  - spec/stubs/fake_request.rb
210
211
  - spec/style_sheet_list_spec.rb
@@ -213,28 +214,26 @@ files:
213
214
  homepage: https://github.com/devrieda/stylesheet
214
215
  licenses:
215
216
  - MIT
216
- post_install_message:
217
+ metadata: {}
218
+ post_install_message:
217
219
  rdoc_options: []
218
220
  require_paths:
219
221
  - lib
220
222
  required_ruby_version: !ruby/object:Gem::Requirement
221
- none: false
222
223
  requirements:
223
- - - ! '>='
224
+ - - ">="
224
225
  - !ruby/object:Gem::Version
225
226
  version: 1.9.3
226
227
  required_rubygems_version: !ruby/object:Gem::Requirement
227
- none: false
228
228
  requirements:
229
- - - ! '>='
229
+ - - ">="
230
230
  - !ruby/object:Gem::Version
231
231
  version: '0'
232
232
  requirements: []
233
- rubyforge_project:
234
- rubygems_version: 1.8.25
235
- signing_key:
236
- specification_version: 3
237
- summary: Stylesheet is a CSS style sheet parser
233
+ rubygems_version: 3.1.2
234
+ signing_key:
235
+ specification_version: 4
236
+ summary: A CSS parser based on the DOM API
238
237
  test_files:
239
238
  - features/document_styles.feature
240
239
  - features/rule_declarations.feature
@@ -287,8 +286,8 @@ test_files:
287
286
  - spec/inflector_spec.rb
288
287
  - spec/location_spec.rb
289
288
  - spec/media_list_spec.rb
289
+ - spec/request_spec.rb
290
290
  - spec/spec_helper.rb
291
291
  - spec/stubs/fake_request.rb
292
292
  - spec/style_sheet_list_spec.rb
293
293
  - spec/version_spec.rb
294
- has_rdoc: