stylesheet 0.1.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.
Files changed (81) hide show
  1. data/.gitignore +20 -0
  2. data/Gemfile +4 -0
  3. data/Guardfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +63 -0
  6. data/Rakefile +22 -0
  7. data/features/document_styles.feature +15 -0
  8. data/features/rule_declarations.feature +9 -0
  9. data/features/step_definitions/document_steps.rb +39 -0
  10. data/features/step_definitions/rule_declaration_steps.rb +13 -0
  11. data/features/step_definitions/style_rule_steps.rb +31 -0
  12. data/features/style_rules.feature +15 -0
  13. data/features/support/env.rb +6 -0
  14. data/lib/stylesheet.rb +35 -0
  15. data/lib/stylesheet/css_charset_rule.rb +24 -0
  16. data/lib/stylesheet/css_font_face_rule.rb +26 -0
  17. data/lib/stylesheet/css_import_rule.rb +41 -0
  18. data/lib/stylesheet/css_media_rule.rb +30 -0
  19. data/lib/stylesheet/css_rule.rb +57 -0
  20. data/lib/stylesheet/css_rule_list.rb +30 -0
  21. data/lib/stylesheet/css_style_declaration.rb +41 -0
  22. data/lib/stylesheet/css_style_rule.rb +29 -0
  23. data/lib/stylesheet/css_style_sheet.rb +100 -0
  24. data/lib/stylesheet/document.rb +63 -0
  25. data/lib/stylesheet/errors.rb +5 -0
  26. data/lib/stylesheet/inflector.rb +11 -0
  27. data/lib/stylesheet/location.rb +113 -0
  28. data/lib/stylesheet/media_list.rb +26 -0
  29. data/lib/stylesheet/request.rb +23 -0
  30. data/lib/stylesheet/style_sheet_list.rb +15 -0
  31. data/lib/stylesheet/version.rb +3 -0
  32. data/spec/css_charset_rule_spec.rb +39 -0
  33. data/spec/css_font_face_rule_spec.rb +47 -0
  34. data/spec/css_import_rule_spec.rb +178 -0
  35. data/spec/css_media_rule_spec.rb +57 -0
  36. data/spec/css_rule_list_spec.rb +74 -0
  37. data/spec/css_rule_spec.rb +102 -0
  38. data/spec/css_style_declaration_spec.rb +71 -0
  39. data/spec/css_style_rule_spec.rb +53 -0
  40. data/spec/css_style_sheet_spec.rb +157 -0
  41. data/spec/document_spec.rb +99 -0
  42. data/spec/fixtures/css/absolute_path.html +14 -0
  43. data/spec/fixtures/css/charset.html +13 -0
  44. data/spec/fixtures/css/font_face.html +13 -0
  45. data/spec/fixtures/css/full_url.html +14 -0
  46. data/spec/fixtures/css/html4.html +15 -0
  47. data/spec/fixtures/css/html5.html +14 -0
  48. data/spec/fixtures/css/inline.html +33 -0
  49. data/spec/fixtures/css/inline_import.html +15 -0
  50. data/spec/fixtures/css/invalid.html +14 -0
  51. data/spec/fixtures/css/media.html +13 -0
  52. data/spec/fixtures/css/relative_path.html +14 -0
  53. data/spec/fixtures/css/stylesheets/charset.css +5 -0
  54. data/spec/fixtures/css/stylesheets/colors.css +0 -0
  55. data/spec/fixtures/css/stylesheets/font_face.css +6 -0
  56. data/spec/fixtures/css/stylesheets/fonts.css +0 -0
  57. data/spec/fixtures/css/stylesheets/media.css +3 -0
  58. data/spec/fixtures/css/stylesheets/print.css +3 -0
  59. data/spec/fixtures/css/stylesheets/screen.css +16 -0
  60. data/spec/fixtures/css_import/index.html +14 -0
  61. data/spec/fixtures/css_import/stylesheets/import1.css +3 -0
  62. data/spec/fixtures/css_import/stylesheets/import2.css +3 -0
  63. data/spec/fixtures/css_import/stylesheets/import3.css +3 -0
  64. data/spec/fixtures/css_import/stylesheets/import4.css +3 -0
  65. data/spec/fixtures/css_import/stylesheets/import5.css +3 -0
  66. data/spec/fixtures/css_import/stylesheets/import6.css +3 -0
  67. data/spec/fixtures/css_import/stylesheets/import7.css +3 -0
  68. data/spec/fixtures/css_import/stylesheets/import8.css +3 -0
  69. data/spec/fixtures/css_import/stylesheets/import9.css +3 -0
  70. data/spec/fixtures/css_import/stylesheets/print.css +3 -0
  71. data/spec/fixtures/css_import/stylesheets/screen.css +15 -0
  72. data/spec/fixtures/fonts/VeraSeBd.ttf +0 -0
  73. data/spec/inflector_spec.rb +17 -0
  74. data/spec/location_spec.rb +260 -0
  75. data/spec/media_list_spec.rb +108 -0
  76. data/spec/spec_helper.rb +10 -0
  77. data/spec/stubs/fake_request.rb +19 -0
  78. data/spec/style_sheet_list_spec.rb +53 -0
  79. data/spec/version_spec.rb +9 -0
  80. data/stylesheet.gemspec +34 -0
  81. metadata +294 -0
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .rvmrc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ .rspec
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ bin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in color_parser.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/stylesheet/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Derek DeVries
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ ## Stylesheet
2
+
3
+ The Stylesheet gem provides a parser for CSS Stylesheets based on the DOM API
4
+
5
+ ## Examples
6
+
7
+ Get styles from a document:
8
+
9
+ ```ruby
10
+ document = Stylesheet::Document.new("http://sportspyder.com")
11
+ document.style_sheets
12
+ ```
13
+
14
+ Get attributes of a stylesheet:
15
+
16
+ ```ruby
17
+ sheet = document.style_sheets[0]
18
+ puts sheet.href
19
+ puts sheet.type
20
+ ```
21
+
22
+ Get stylesheet media definitions:
23
+
24
+ ```ruby
25
+ sheet = document.style_sheets[0]
26
+ sheet.media.each do |media|
27
+ puts media
28
+ end
29
+ ```
30
+
31
+ Get rules defined in a stylesheet:
32
+
33
+ ```ruby
34
+ 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
39
+ ```
40
+
41
+ Get declarations defined in a style rules:
42
+
43
+ ```ruby
44
+ sheet = document.style_sheets[0]
45
+ rule = sheet.css_rules[0]
46
+ puts rule.style[0]
47
+ puts rule.style.border
48
+ ```
49
+
50
+ ## Installation
51
+
52
+ ```
53
+ gem install stylesheet
54
+ ```
55
+ ```
56
+ gem "stylesheet"
57
+ ```
58
+
59
+ ## LICENSE
60
+
61
+ Copyright (c) 2013 Derek DeVries
62
+
63
+ Released under the [MIT License](http://www.opensource.org/licenses/MIT)
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ namespace :spec do
9
+ desc 'Run unit specs only'
10
+ RSpec::Core::RakeTask.new(:unit) do |task|
11
+ task.pattern = 'spec'
12
+ task.rspec_opts = '--tag "~live"'
13
+ end
14
+
15
+ desc 'Run acceptance specs only'
16
+ RSpec::Core::RakeTask.new(:acceptance) do |task|
17
+ task.pattern = 'spec'
18
+ task.rspec_opts = '--tag "live"'
19
+ end
20
+ end
21
+
22
+ task :default => :spec
@@ -0,0 +1,15 @@
1
+ Feature: find stylesheets from documents
2
+ In order to find visual components of a website
3
+ As a developer
4
+ I want to find the stylesheets in a document
5
+
6
+ Scenario: find document styles
7
+ Given I have a document at the url http://example.com/css/absolute_path.html
8
+ When I ask for style sheets
9
+ Then I should receive a list of stylesheets
10
+
11
+ Scenario: find stylesheet attributes
12
+ Given I have a css file found in the document http://example.com/css/absolute_path.html
13
+ When I ask the stylesheet about it's attributes
14
+ Then I should get details about the stylesheet
15
+ And the media the stylesheet was intended for
@@ -0,0 +1,9 @@
1
+ Feature: find declarations defined in a style rules
2
+ In order to find visual components of a website
3
+ As a developer
4
+ I want to find the css rule declarations in a style rule
5
+
6
+ Scenario: find declarations in style rules
7
+ Given I have a rule in the css file at the url http://example.com/css/stylesheets/screen.css
8
+ When I ask a rule about it's styles
9
+ Then I should get style declarations
@@ -0,0 +1,39 @@
1
+ Before do
2
+ Stylesheet.request = FakeRequest.new
3
+ end
4
+
5
+ Given(/^I have a document at the url (.*)$/) do |url|
6
+ @document = Document.new(url)
7
+ end
8
+
9
+ When(/^I ask for style sheets$/) do
10
+ @sheets = @document.style_sheets
11
+ end
12
+
13
+ Then(/^I should receive a list of stylesheets$/) do
14
+ expect(@sheets).to be_kind_of(StyleSheetList)
15
+ end
16
+
17
+ Given(/^I have a css file found in the document (.*)$/) do |url|
18
+ @stylesheet = Document.new(url).style_sheets[0]
19
+ end
20
+
21
+ When(/^I ask the stylesheet about it's attributes$/) do
22
+ @type = @stylesheet.type
23
+ @href = @stylesheet.href
24
+ @disabled = @stylesheet.disabled?
25
+ @rules = @stylesheet.css_rules
26
+
27
+ @media = @stylesheet.media
28
+ end
29
+
30
+ Then(/^I should get details about the stylesheet$/) do
31
+ expect(@type).to eq "text/css"
32
+ expect(@href).to eq "http://example.com/css/stylesheets/screen.css"
33
+ expect(@disabled).to be_false
34
+ expect(@rules).to be_kind_of(CssRuleList)
35
+ end
36
+
37
+ Then(/^the media the stylesheet was intended for$/) do
38
+ expect(@media).to be_kind_of(MediaList)
39
+ end
@@ -0,0 +1,13 @@
1
+ Before do
2
+ Stylesheet.request = FakeRequest.new
3
+ end
4
+
5
+ When(/^I ask a rule about it's styles$/) do
6
+ @declarations = @rule.style
7
+ end
8
+
9
+ Then(/^I should get style declarations$/) do
10
+ expect(@declarations.css_text).to eq "color: #444; background-color: #535353;"
11
+ expect(@declarations[0]).to eq "color: #444"
12
+ expect(@declarations.color).to eq "#444"
13
+ end
@@ -0,0 +1,31 @@
1
+ Before do
2
+ Stylesheet.request = FakeRequest.new
3
+ end
4
+
5
+ Given(/^I have a css file at the url (.*)$/) do |url|
6
+ @stylesheet = CssStyleSheet.new(url)
7
+ end
8
+
9
+ When(/^I ask the style about it's rules$/) do
10
+ @rules = @stylesheet.css_rules
11
+ end
12
+
13
+ Then(/^I should receive a list of style rules$/) do
14
+ expect(@rules).to be_kind_of CssRuleList
15
+ end
16
+
17
+ Given(/^I have a rule in the css file at the url (.*)$/) do |url|
18
+ @rule = CssStyleSheet.new(url).css_rules[0]
19
+ end
20
+
21
+ When(/^I ask the rule about it's attributes$/) do
22
+ @css_text = @rule.css_text
23
+ @selector = @rule.selector_text
24
+ @type = @rule.type
25
+ end
26
+
27
+ Then(/^I should get details about the rule$/) do
28
+ expect(@css_text).to eq "body { color: #444;background-color: #535353;}"
29
+ expect(@selector).to eq "body"
30
+ expect(@type).to eq CssRule::STYLE_RULE
31
+ end
@@ -0,0 +1,15 @@
1
+ Feature: find rules defined in a stylesheet
2
+ In order to find visual components of a website
3
+ As a developer
4
+ I want to find style rules in a stylesheet
5
+
6
+ Scenario: find rules in a stylesheet
7
+ Given I have a css file at the url http://example.com/css/stylesheets/screen.css
8
+ When I ask the style about it's rules
9
+ Then I should receive a list of style rules
10
+
11
+ Scenario: find rule attributes
12
+ Given I have a rule in the css file at the url http://example.com/css/stylesheets/screen.css
13
+ When I ask the rule about it's attributes
14
+ Then I should get details about the rule
15
+
@@ -0,0 +1,6 @@
1
+ require 'rspec/expectations'
2
+
3
+ require_relative '../../lib/stylesheet'
4
+ require_relative '../../spec/stubs/fake_request'
5
+
6
+ include Stylesheet
data/lib/stylesheet.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'uri'
2
+ require 'forwardable'
3
+ require 'curb'
4
+ require 'nokogiri'
5
+
6
+ require 'stylesheet/errors'
7
+ require 'stylesheet/version'
8
+ require 'stylesheet/inflector'
9
+ require 'stylesheet/request'
10
+ require 'stylesheet/document'
11
+ require 'stylesheet/location'
12
+
13
+ require 'stylesheet/style_sheet_list'
14
+ require 'stylesheet/css_style_sheet'
15
+ require 'stylesheet/media_list'
16
+
17
+ require 'stylesheet/css_rule_list'
18
+ require 'stylesheet/css_rule'
19
+ require 'stylesheet/css_style_rule'
20
+ require 'stylesheet/css_charset_rule'
21
+ require 'stylesheet/css_import_rule'
22
+ require 'stylesheet/css_media_rule'
23
+ require 'stylesheet/css_font_face_rule'
24
+
25
+ require 'stylesheet/css_style_declaration'
26
+
27
+ module Stylesheet
28
+ def self.request=(request)
29
+ @request = request
30
+ end
31
+
32
+ def self.request
33
+ @request ||= Request.new
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module Stylesheet
2
+ class CssCharsetRule < CssRule
3
+
4
+ attr_reader :encoding
5
+
6
+ def type
7
+ CssRule::CHARSET_RULE
8
+ end
9
+
10
+ def self.matches_rule?(text)
11
+ text.include?("@charset")
12
+ end
13
+
14
+ private
15
+
16
+ def encoding=(encoding)
17
+ @encoding = encoding.gsub(/["']+/, "")
18
+ end
19
+
20
+ def parse_css_text
21
+ selector, self.encoding = css_text.gsub(";", "").split(" ", 2)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ module Stylesheet
2
+ class CssFontFaceRule < CssRule
3
+
4
+ def type
5
+ CssRule::FONT_FACE_RULE
6
+ end
7
+
8
+ def style
9
+ CssStyleDeclaration.new(:css_text => @declarations,
10
+ :parent_rule => self)
11
+ end
12
+
13
+ def self.matches_rule?(text)
14
+ text.include?("@font-face")
15
+ end
16
+
17
+ private
18
+
19
+ def parse_css_text
20
+ return unless css_text.include?("{")
21
+
22
+ selector, declarations = css_text.split("{")
23
+ @declarations = declarations.strip.gsub(/\}\s*$/, "")
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ module Stylesheet
2
+ class CssImportRule < CssRule
3
+
4
+ attr_reader :media
5
+
6
+ def type
7
+ CssRule::IMPORT_RULE
8
+ end
9
+
10
+ def href
11
+ @href
12
+ end
13
+
14
+ def style_sheet
15
+ @style_sheet ||= CssStyleSheet.new(location.href)
16
+ end
17
+
18
+ def self.matches_rule?(text)
19
+ text.include?("@import")
20
+ end
21
+
22
+ def location
23
+ @location ||= Location.new(@href,
24
+ parent_style_sheet && parent_style_sheet.location)
25
+ end
26
+
27
+ private
28
+
29
+ def href=(url)
30
+ @href = url.gsub(/url\(|\)|['";]+/, "")
31
+ end
32
+
33
+ def media=(media)
34
+ @media = MediaList.new(media)
35
+ end
36
+
37
+ def parse_css_text
38
+ selector, self.href, self.media = css_text.gsub(";", "").split(" ", 3)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ module Stylesheet
2
+ class CssMediaRule < CssRule
3
+
4
+ attr_reader :content
5
+
6
+ def type
7
+ CssRule::MEDIA_RULE
8
+ end
9
+
10
+ def css_rules
11
+ @css_rules ||= CssRuleList.new(content)
12
+ end
13
+
14
+ def self.matches_rule?(text)
15
+ text.include?("@media")
16
+ end
17
+
18
+ private
19
+
20
+ def parse_css_text
21
+ return unless css_text.include?("{")
22
+
23
+ @content = if matches = css_text.match(/\{(.*)\}/mi)
24
+ matches[1]
25
+ else
26
+ ""
27
+ end
28
+ end
29
+ end
30
+ end