stylesheet 0.1.0

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