style_cop 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cad754b549725a014e392f631d97c12dbb12dfc8
4
- data.tar.gz: aba58cb8317eacd9a5d90b97ee02e5e4352f8974
3
+ metadata.gz: 8ccd9358deff944371ff06fcc84ad663b589c577
4
+ data.tar.gz: e293278f633c29acef072db79cac6880e4f7b9cd
5
5
  SHA512:
6
- metadata.gz: a2a236e98c7fc36371c3c468d6f25e8315f5473326085d7a10a289dc8bbbe51e300f5b7cfcc5312191163aeeaf07f3fb4f8ede8cad7dfe54e7548bded8a99225
7
- data.tar.gz: a88d3a48dd18d12f03e416393c32d728b6f068f6a524b5dfc25c1888c05e6e849ba0a66f66ded8a59bc93066fd22cc3bad02a2da2aa145adff436fc038efece7
6
+ metadata.gz: e6005e11b8f026750264a673e4943c3c01e5c91553949c7c7257633ed9d5ba3932a53645110789b3e810aef7ad307bb3bfa89893dd91cc7eecf15695054f1b87
7
+ data.tar.gz: f532b4948694b8b5215b206c136bf5701ec6637c817db760ea78a202453ea337737fdc70e5d37b13de86d8c255463026ec295f173b9fe72f8b8ce935309a11ff
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ style_cop-0.0.1.gem
2
+ .DS_Store
3
+ Gemfile.lock
data/.pairs ADDED
@@ -0,0 +1,10 @@
1
+ pairs:
2
+ dt: David Tegdin; dtegdin
3
+ wp: Ward Penney; wpenney
4
+ jn: Jordi Noguera; jordi
5
+
6
+ email:
7
+ prefix: style_cop+pair
8
+ domain: pivotallabs.com
9
+
10
+ global: true
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/README.md CHANGED
@@ -1,2 +1,46 @@
1
1
  # style_cop
2
- Police your style!
2
+ Style Cop helps you enforce markup structure for front-end patterns via Rspec and Capybara. You spent all that time making your CSS play nicely. If all developers use the markup correctly, then it will render beautifully!
3
+
4
+ ## Hypothesis
5
+
6
+ 1. We believe developers / designers have a problem sticiking w established DOM patterns, rather than page-overriding to tweak style.
7
+ 2. We can fix it by creating momentum to "use or improve" front-end CSS patterns by breaking the build if a pattern is used incorrectly
8
+ 3. We know we are right if a team thinks this is a good idea and uses it on a project, and they tweet a link to the repo.
9
+
10
+ ## MVP
11
+
12
+ What's the least amount of work we can do to in/vadidate this hypothesis?
13
+
14
+ * A gem that targets Rails projects that use Hologram
15
+ * It automagically "enforces" DOM and style as defined in the Hologram live style guide
16
+
17
+ ## Installation
18
+
19
+ Note: StyleCop depends on CapybaraWebkit so you will need to make sure that installs first: https://github.com/thoughtbot/capybara-webkit
20
+
21
+ Put into your gemfile
22
+
23
+ gem style_cop
24
+
25
+ Bundle
26
+
27
+ $ bundle
28
+
29
+ ## Getting Started
30
+
31
+ To test a selector on your page matches the same selector on your styleguide
32
+ you will need to do two things:
33
+
34
+ 1. Add the class 'style-cop-pattern' to the selector in your styleguide
35
+
36
+ 2. Add code like this somewhere in an integration test:
37
+
38
+ '''
39
+ context "some context", style_cop: true do
40
+ it "tests something" do
41
+ visit "/some/path"
42
+ selector = page.find(".your-selector")
43
+ expect(selector).to match_styleguide(styleguide_page("/your/styleguide/path"))
44
+ end
45
+ end
46
+ '''
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |config|
2
+ config.before(:each, style_cop: true) do
3
+ Capybara.current_driver = :webkit
4
+ end
5
+
6
+ config.after(:each, style_cop: true) do
7
+ Capybara.use_default_driver
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module StyleCop
2
+ module Helpers
3
+ def styleguide_page(path)
4
+ old_session_name = Capybara.session_name
5
+ Capybara.session_name = "styleguide"
6
+ Capybara.visit path
7
+ Capybara.page.tap { Capybara.session_name = old_session_name }
8
+ end
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.include(StyleCop::Helpers, style_cop: true)
14
+ end
@@ -0,0 +1,16 @@
1
+ RSpec::Matchers.define :match_styleguide do |capybara_styleguide|
2
+ match do |capybara_selector|
3
+ selector = StyleCop::Selector.new(capybara_selector)
4
+ styleguide = StyleCop::StyleGuide.new(capybara_styleguide)
5
+ styleguide_selector = styleguide.find(selector.key)
6
+ StyleCop::SelectorDifference.new(selector, styleguide_selector).empty?
7
+ end
8
+
9
+ failure_message_for_should do |capybara_selector|
10
+ selector = StyleCop::Selector.new(capybara_selector)
11
+ styleguide = StyleCop::StyleGuide.new(capybara_styleguide)
12
+ styleguide_selector = styleguide.find(selector.key)
13
+ StyleCop::SelectorDifference.new(selector, styleguide_selector).error_message
14
+ end
15
+ end
16
+
@@ -0,0 +1,68 @@
1
+ module StyleCop
2
+ class Selector
3
+ EXCLUDED_KEYS = ["width", "height", "top", "bottom", "right", "left"]
4
+
5
+ def initialize(selector)
6
+ @selector = selector
7
+ end
8
+
9
+ def key
10
+ if selector['class']
11
+ ".#{selector['class'].gsub(' ', '.')}"
12
+ elsif selector['id']
13
+ "##{selector['id']}"
14
+ else
15
+ selector.tag_name
16
+ end
17
+ end
18
+
19
+ def representation
20
+ clean_key = key.gsub(".style-cop-pattern", "")
21
+ return { clean_key => computed_style } if children.empty?
22
+ children_hash = children.map(&:representation).inject({}) { |hash, h| hash.merge!(h) }
23
+ Hash[children_hash.map { |key, value| ["#{clean_key} #{key}", value] }].merge(
24
+ clean_key => computed_style
25
+ )
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :selector
31
+
32
+ def computed_style
33
+ style_hash.tap do |hash|
34
+ EXCLUDED_KEYS.each { |key| hash.delete(key) }
35
+ end
36
+ end
37
+
38
+ def children
39
+ selector.all(:xpath, "#{selector.path}/*").map do |child|
40
+ Selector.new(child)
41
+ end
42
+ end
43
+
44
+ def style_hash
45
+ Hash[css.split(/\s*;\s*/).map { |s| s.split(/\s*:\s*/) }]
46
+ end
47
+
48
+ def css
49
+ if computed_style = session.evaluate_script(computed_style_script)
50
+ computed_style["cssText"]
51
+ else
52
+ raise RuntimeError.new("Can't find css for #{selector.key}")
53
+ end
54
+ end
55
+
56
+ def session
57
+ selector.session
58
+ end
59
+
60
+ def computed_style_script
61
+ %{
62
+ var node = document.evaluate("/#{selector.path}",
63
+ document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue
64
+ window.getComputedStyle(node);
65
+ }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,56 @@
1
+ module StyleCop
2
+ class SelectorDifference
3
+ MISSING_CSS_TEXT = "element is missing the following css"
4
+ EXTRA_CSS_TEXT = "element has the following extra css"
5
+ MISSING_STRUCTURE_TEXT = "element is missing the following structure piece"
6
+ EXTRA_STRUCTURE_TEXT = "element has the following extra structure piece"
7
+
8
+ def initialize(selector, other_selector)
9
+ @selector = selector
10
+ @other_selector = other_selector
11
+ end
12
+
13
+ def empty?
14
+ selector.representation == other_selector.representation
15
+ end
16
+
17
+ def error_message
18
+ (css_errors + structure_errors).join(", ")
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :selector, :other_selector
24
+
25
+ def structure_errors
26
+ errors = []
27
+ extra_elements = selector.representation.keys - other_selector.representation.keys
28
+ missing_elements = other_selector.representation.keys - selector.representation.keys
29
+ errors << "The #{selector.key} #{EXTRA_STRUCTURE_TEXT}: #{extra_elements.join(", ")}" if extra_elements.any?
30
+ errors << "The #{selector.key} #{MISSING_STRUCTURE_TEXT}: #{missing_elements.join(", ")}" if missing_elements.any?
31
+ errors
32
+ end
33
+
34
+ def css_errors
35
+ errors = []
36
+ css_difference(other_selector, selector).each do |path, extra_css|
37
+ errors << "The #{selector.key} #{EXTRA_CSS_TEXT}: #{extra_css.map{|k,v| "#{k}: #{v}"}.join(', ')}" unless extra_css.empty?
38
+ end
39
+ css_difference(selector, other_selector).each do |path, extra_css|
40
+ errors << "The #{selector.key} #{MISSING_CSS_TEXT}: #{extra_css.map{|k,v| "#{k}: #{v}"}.join(', ')}" unless extra_css.empty?
41
+ end
42
+ errors
43
+ end
44
+
45
+ def css_difference(selector1, selector2)
46
+ difference = {}
47
+ selector2_representation = selector2.representation
48
+ selector1.representation.each do |path, selector1_css|
49
+ if selector2_css = selector2_representation[path]
50
+ difference[path] = Hash[selector2_css.to_a - selector1_css.to_a]
51
+ end
52
+ end
53
+ difference
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ module StyleCop
2
+ class StyleGuide
3
+ def initialize(styleguide)
4
+ @styleguide = styleguide
5
+ end
6
+
7
+ def find(selector_key)
8
+ Selector.new(styleguide.find("#{selector_key}.style-cop-pattern"))
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :styleguide
14
+ end
15
+ end
data/lib/style_cop.rb CHANGED
@@ -1,10 +1,9 @@
1
- module StyleCop
2
- require 'style_cop/assert_style'
3
- require 'style_cop/register_style'
4
- require 'style_cop/public_methods'
5
- end
1
+ require "style_cop/capybara_webkit"
2
+ require "style_cop/selector"
3
+ require "style_cop/style_guide"
4
+ require "style_cop/match_styleguide_matcher"
5
+ require "style_cop/selector_difference"
6
+ require "style_cop/helpers"
6
7
 
7
- RSpec.configure do |c|
8
- c.include StyleCop::PublicMethods, type: :feature
8
+ module StyleCop
9
9
  end
10
-
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ module StyleCop
4
+ describe "MatchStyleguideMatcher" do
5
+ it "includes the matcher" do
6
+ expect(self).to respond_to(:match_styleguide)
7
+ end
8
+
9
+ context "when the selectors matches the styleguide" do
10
+ let(:html) do
11
+ create_html({
12
+ body: %(
13
+ <div class='selector'></div>
14
+ <div class='selector style-cop-pattern'></div>
15
+ )
16
+ })
17
+ end
18
+ let(:page) { FakePage.new(html) }
19
+ let(:selector) { page.all(".selector").first }
20
+
21
+ it "passes" do
22
+ expect(selector).to match_styleguide(page)
23
+ end
24
+ end
25
+
26
+ context "when the selector doesn't match the styleguide" do
27
+ let(:html) do
28
+ create_html({
29
+ body: %(
30
+ <div class='selector'></div>
31
+ <div class='selector style-cop-pattern'><div class='wrong'></div></div>
32
+ )
33
+ })
34
+ end
35
+
36
+ let(:page) { FakePage.new(html) }
37
+ let(:selector) { page.all(".selector").first }
38
+ let(:styleguide_selector) { page.find(".selector.style-cop-pattern") }
39
+ let(:selector_difference) { double(SelectorDifference, empty?: false) }
40
+
41
+ it "doesn't pass" do
42
+ expect(selector).to_not match_styleguide(page)
43
+ end
44
+
45
+ it "displays error messages when matcher fails" do
46
+ allow(SelectorDifference).to receive(:new).
47
+ and_return(selector_difference)
48
+ expect(selector_difference).to receive(:error_message) { "selector to match" }
49
+
50
+ expect {
51
+ expect(selector).to match_styleguide(page)
52
+ }.to raise_error(/selector to match/)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ module StyleCop
4
+ describe SelectorDifference do
5
+ let(:selector) { double }
6
+ let(:styleguide_selector) { double }
7
+ subject { SelectorDifference.new(selector, styleguide_selector) }
8
+
9
+ describe "#error_message" do
10
+ before do
11
+ allow(selector).to receive(:key).and_return(".structure")
12
+ allow(selector).to receive(:representation).and_return(selector_representation)
13
+ allow(styleguide_selector).to receive(:representation).and_return(styleguide_representation)
14
+ end
15
+
16
+ context "css" do
17
+ context "missing styleguide css" do
18
+ let(:selector_representation) { { ".selector" => {"a"=>"b"} } }
19
+ let(:styleguide_representation) { { ".selector" => {"a"=>"b", "font-size"=>"100px"} } }
20
+
21
+ it "shows what css the element is missing" do
22
+ message = "The .structure element is missing the following css: font-size: 100px"
23
+ expect(subject.error_message).to eq message
24
+ end
25
+ end
26
+
27
+ context "extra css not in styleguide" do
28
+ let(:selector_representation) { { ".selector" => {"a"=>"b", "font-size"=>"100px"} } }
29
+ let(:styleguide_representation) { { ".selector" => {"a"=>"b"} } }
30
+
31
+ it "shows what extra css is present" do
32
+ message = "The .structure element has the following extra css: font-size: 100px"
33
+ expect(subject.error_message).to eq message
34
+ end
35
+ end
36
+
37
+ context "missing css in the styleguide and has extra css not in the styleguide" do
38
+ let(:selector_representation) { {".selector" => { "font-size"=>"100px"} } }
39
+ let(:styleguide_representation) { {".selector" => { "font-size"=>"80px"} } }
40
+
41
+ it "shows what extra css is present" do
42
+ message = "The .structure element has the following extra css: font-size: 100px, The .structure element is missing the following css: font-size: 80px"
43
+ expect(subject.error_message).to include message
44
+ end
45
+ end
46
+ end
47
+
48
+ context "structure" do
49
+ context "missing styleguide structure" do
50
+ let(:selector_representation) { { ".selector .child" => {} } }
51
+ let(:styleguide_representation) { { ".selector .child" => {}, ".selector .child .missing" => {} } }
52
+
53
+ it "shows what structure is missing from the element" do
54
+ message = "The .structure element is missing the following structure piece: .selector .child .missing"
55
+ expect(subject.error_message).to eq message
56
+ end
57
+ end
58
+
59
+ context "extra structure not in styleguide" do
60
+ let(:selector_representation) { { ".selector .child" => {}, ".selector .child .extra" => {} } }
61
+ let(:styleguide_representation) { { ".selector .child" => {} } }
62
+
63
+ it "shows what extra structure is present" do
64
+ message = "The .structure element has the following extra structure piece: .selector .child .extra"
65
+ expect(subject.error_message).to eq message
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#empty?" do
72
+ let(:first_selector) { Selector.new page.all(".selector").first }
73
+ let(:last_selector) { Selector.new page.all(".selector").last }
74
+ let(:page) { FakePage.new(html) }
75
+ subject { SelectorDifference.new(first_selector, last_selector) }
76
+
77
+ context "when two selectors have same css" do
78
+ let(:html) do
79
+ create_html({
80
+ body: %{
81
+ <div class="selector"></div>
82
+ <div class="selector"></div>
83
+ }
84
+ })
85
+ end
86
+
87
+ it "returns true" do
88
+ expect(subject).to be_empty
89
+ end
90
+ end
91
+
92
+ context "when two selectors don't have same css" do
93
+ let(:html) do
94
+ create_html({
95
+ body: %{
96
+ <div class="selector"></div>
97
+ <div class="selector" style="font-size: 100px"></div>
98
+ }
99
+ })
100
+ end
101
+
102
+ it "returns false" do
103
+ expect(subject).to_not be_empty
104
+ end
105
+ end
106
+
107
+ context "when two selectors have same structure" do
108
+ let(:html) do
109
+ create_html({
110
+ body: %{
111
+ <div class="selector"><div class="child2"></div></div>
112
+ <div class="selector"><div class="child2"></div></div>
113
+ }
114
+ })
115
+ end
116
+
117
+ it "returns true" do
118
+ expect(subject).to be_empty
119
+ end
120
+ end
121
+
122
+ context "when two selectors don't have same structure" do
123
+ let(:html) do
124
+ create_html({
125
+ body: %{
126
+ <div class="selector"></div>
127
+ <div class="selector"><div class="child2"></div></div>
128
+ }
129
+ })
130
+ end
131
+
132
+ it "returns false" do
133
+ expect(subject).to_not be_empty
134
+ end
135
+ end
136
+
137
+ context "when two selectors children have same css" do
138
+ let(:html) do
139
+ create_html({
140
+ body: %{
141
+ <div class="selector"><div class="child2"></div></div>
142
+ <div class="selector"><div class="child2"></div></div>
143
+ }
144
+ })
145
+ end
146
+
147
+ it "returns false" do
148
+ expect(subject).to be_empty
149
+ end
150
+ end
151
+
152
+ context "when two selectors children don't have same css" do
153
+ let(:html) do
154
+ create_html({
155
+ body: %{
156
+ <div class="selector"><div class="child2"></div></div>
157
+ <div class="selector"><div class="child2" style="font-size:100px"></div></div>
158
+ }
159
+ })
160
+ end
161
+
162
+ it "returns false" do
163
+ expect(subject).to_not be_empty
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ module StyleCop
4
+ describe Selector, style_cop: true do
5
+ describe "#key" do
6
+ let(:page) { FakePage.new(selector_html) }
7
+ let(:capybara_selector) { page.find("span") }
8
+ let(:selector) { Selector.new(capybara_selector) }
9
+
10
+ context "for a class" do
11
+ let(:selector_html) do
12
+ create_html(body: "<span class='selector other-selector' id='ignored'></span>")
13
+ end
14
+
15
+ it "returns the classes separated by a dot" do
16
+ expect(selector.key).to eq(".selector.other-selector")
17
+ end
18
+ end
19
+
20
+ context "for an id" do
21
+ let(:selector_html) do
22
+ create_html(body: "<span id='selector'></span>")
23
+ end
24
+
25
+ it "returns the id prefixed by a pound" do
26
+ expect(selector.key).to eq("#selector")
27
+ end
28
+ end
29
+
30
+ context "for an html element" do
31
+ let(:selector_html) do
32
+ create_html(body: "<span></span>")
33
+ end
34
+
35
+ it "returns html element" do
36
+ expect(selector.key).to eq("span")
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#representation" do
42
+ let(:html) do
43
+ create_html({
44
+ body: %{
45
+ <div class="selector style-cop-pattern" style="font-size:16px">
46
+ <div class="child1" style="font-size:24px">
47
+ <div class="child3 style-cop-pattern" style="font-size:36px"></div>
48
+ </div>
49
+ <div class="child2"></div>
50
+ </div>
51
+ }
52
+ })
53
+ end
54
+
55
+ let(:page) { FakePage.new(html) }
56
+ let(:selector) { Selector.new page.find(".selector") }
57
+
58
+ it "returns a hash with structure keys andd css values" do
59
+ expect(selector.representation.keys.sort).to eq(
60
+ [".selector", ".selector .child1", ".selector .child1 .child3", ".selector .child2"]
61
+ )
62
+ expect(selector.representation[".selector"]["font-size"]).to eq("16px")
63
+ expect(selector.representation[".selector .child1"]["font-size"]).to eq("24px")
64
+ expect(selector.representation[".selector .child1 .child3"]["font-size"]).to eq("36px")
65
+ expect(selector.representation[".selector .child2"]["font-size"]).to eq("16px")
66
+ end
67
+
68
+ context "excluded keys in style" do
69
+ let(:html) do
70
+ create_html({
71
+ body: %{
72
+ <div class="selector"></div>
73
+ }
74
+ })
75
+ end
76
+
77
+ let(:selector) { Selector.new(page.find(".selector")) }
78
+ subject { selector.representation['.selector'] }
79
+
80
+ it { should_not have_key("width") }
81
+ it { should_not have_key("height") }
82
+ it { should_not have_key("top") }
83
+ it { should_not have_key("bottom") }
84
+ it { should_not have_key("right") }
85
+ it { should_not have_key("left") }
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe StyleCop do
4
+ context "capybara driver" do
5
+ it "doesn't change the current driver by default" do
6
+ expect(Capybara.current_driver).to_not eq(:webkit)
7
+ end
8
+
9
+ it "changes to current driver for style cop specs", style_cop: true do
10
+ expect(Capybara.current_driver).to eq(:webkit)
11
+ end
12
+ end
13
+
14
+ context "styleguide_page" do
15
+ it "doesn't add the helper method for non-style cop tests" do
16
+ expect(self).to_not respond_to(:styleguide_page)
17
+ end
18
+
19
+ context "style cop tests", style_cop: true do
20
+ it "have a styleguide_page method" do
21
+ Capybara.app = FakePage::TestApp
22
+ Capybara.app.set_html("<html></html>")
23
+ expect(styleguide_page("/")).to_not be_nil
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ module StyleCop
4
+ describe StyleGuide do
5
+ describe "#find" do
6
+ let(:styleguide_html) do
7
+ create_html({
8
+ body: %{
9
+ <div class="selector first style-cop-pattern"></div>
10
+ <div class="selector second style-cop-pattern"></div>
11
+ }
12
+ })
13
+ end
14
+
15
+ let(:styleguide_page) { FakePage.new(styleguide_html) }
16
+ let(:styleguide) { StyleGuide.new(styleguide_page) }
17
+
18
+ it "finds elements in the styleguide by key" do
19
+ expect(styleguide.find(".selector.first").key).to eq(".selector.first.style-cop-pattern")
20
+ end
21
+ end
22
+ end
23
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,16 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
1
+ require "rubygems"
2
+ require "bundler/setup"
3
3
 
4
- require 'pry'
5
- require 'style_cop'
6
- require 'rspec'
4
+ require "pry"
5
+ require "style_cop"
6
+ require "rspec"
7
+ require "capybara"
8
+ require "capybara-webkit"
9
+ require "sinatra"
7
10
 
8
- ENV['test_run'] = true.to_s
11
+ ENV["test_run"] = true.to_s
9
12
 
10
- Dir[File.join(File.dirname(__FILE__), 'support', '**', '*.rb')].each do |file|
13
+ Dir[File.join(File.dirname(__FILE__), "support", "**", "*.rb")].each do |file|
11
14
  require file
12
15
  end
13
16
 
@@ -0,0 +1,21 @@
1
+ class FakePage
2
+ def initialize(html)
3
+ @session = Capybara::Session.new(:webkit, TestApp)
4
+ @session.app.set_html(html)
5
+ @session.visit "/"
6
+ end
7
+
8
+ def method_missing(method, *args)
9
+ @session.public_send(method, *args)
10
+ end
11
+
12
+ class TestApp < Sinatra::Base
13
+ def self.set_html(html)
14
+ @@html = html
15
+ end
16
+
17
+ get '/' do
18
+ @@html
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module HtmlHelpers
2
+ def create_html(options = {})
3
+ %{<html>
4
+ <head>
5
+ <style>
6
+ #{options[:style]}
7
+ </style>
8
+ </head>
9
+ <body>
10
+ #{options[:body]}
11
+ </body>
12
+ </html>}
13
+ end
14
+ end
15
+
16
+ RSpec.configure do |config|
17
+ config.include(HtmlHelpers)
18
+ end
data/style_cop.gemspec CHANGED
@@ -1,16 +1,18 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'style_cop'
3
- s.version = '0.0.1'
3
+ s.version = '0.0.2'
4
4
  s.date = '2014-03-03'
5
5
  s.summary = "Gem for testing style"
6
6
  s.description = "Gem for testing style"
7
- s.authors = ["Ward Penney", "David Tengdin"]
7
+ s.authors = ["Ward Penney", "David Tengdin", "Jordi Noguera"]
8
8
  s.email = 'style-cop@googlegroups.com'
9
9
  s.files = `git ls-files`.split("\n")
10
10
  s.homepage = 'http://rubygems.org/gems/style_cop'
11
11
  s.license = 'MIT'
12
12
 
13
- s.add_development_dependency "rspec", "~> 2.14.0"
14
- s.add_development_dependency "xpath", "~> 2.0.0"
15
- s.add_development_dependency "pry", "~> 0.9.12.6"
13
+ s.add_dependency "rspec"
14
+ s.add_dependency "capybara-webkit"
15
+
16
+ s.add_development_dependency "pry"
17
+ s.add_development_dependency "sinatra"
16
18
  end
metadata CHANGED
@@ -1,11 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: style_cop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ward Penney
8
8
  - David Tengdin
9
+ - Jordi Noguera
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
@@ -15,60 +16,84 @@ dependencies:
15
16
  name: rspec
16
17
  requirement: !ruby/object:Gem::Requirement
17
18
  requirements:
18
- - - ~>
19
+ - - ">="
19
20
  - !ruby/object:Gem::Version
20
- version: 2.14.0
21
- type: :development
21
+ version: '0'
22
+ type: :runtime
22
23
  prerelease: false
23
24
  version_requirements: !ruby/object:Gem::Requirement
24
25
  requirements:
25
- - - ~>
26
+ - - ">="
26
27
  - !ruby/object:Gem::Version
27
- version: 2.14.0
28
+ version: '0'
28
29
  - !ruby/object:Gem::Dependency
29
- name: xpath
30
+ name: capybara-webkit
30
31
  requirement: !ruby/object:Gem::Requirement
31
32
  requirements:
32
- - - ~>
33
+ - - ">="
33
34
  - !ruby/object:Gem::Version
34
- version: 2.0.0
35
- type: :development
35
+ version: '0'
36
+ type: :runtime
36
37
  prerelease: false
37
38
  version_requirements: !ruby/object:Gem::Requirement
38
39
  requirements:
39
- - - ~>
40
+ - - ">="
40
41
  - !ruby/object:Gem::Version
41
- version: 2.0.0
42
+ version: '0'
42
43
  - !ruby/object:Gem::Dependency
43
44
  name: pry
44
45
  requirement: !ruby/object:Gem::Requirement
45
46
  requirements:
46
- - - ~>
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: sinatra
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
47
62
  - !ruby/object:Gem::Version
48
- version: 0.9.12.6
63
+ version: '0'
49
64
  type: :development
50
65
  prerelease: false
51
66
  version_requirements: !ruby/object:Gem::Requirement
52
67
  requirements:
53
- - - ~>
68
+ - - ">="
54
69
  - !ruby/object:Gem::Version
55
- version: 0.9.12.6
70
+ version: '0'
56
71
  description: Gem for testing style
57
72
  email: style-cop@googlegroups.com
58
73
  executables: []
59
74
  extensions: []
60
75
  extra_rdoc_files: []
61
76
  files:
77
+ - ".gitignore"
78
+ - ".pairs"
79
+ - ".rspec"
62
80
  - Gemfile
63
- - Gemfile.lock
64
81
  - README.md
65
82
  - lib/style_cop.rb
66
- - lib/style_cop/assert_style.rb
67
- - lib/style_cop/public_methods.rb
68
- - lib/style_cop/register_style.rb
69
- - spec/lib/style_cop/assert_style_spec.rb
70
- - spec/lib/style_cop/public_methods_spec.rb
83
+ - lib/style_cop/capybara_webkit.rb
84
+ - lib/style_cop/helpers.rb
85
+ - lib/style_cop/match_styleguide_matcher.rb
86
+ - lib/style_cop/selector.rb
87
+ - lib/style_cop/selector_difference.rb
88
+ - lib/style_cop/style_guide.rb
89
+ - spec/lib/match_styleguide_matcher_spec.rb
90
+ - spec/lib/selector_difference_spec.rb
91
+ - spec/lib/selector_spec.rb
92
+ - spec/lib/style_cop_spec.rb
93
+ - spec/lib/style_guide_spec.rb
71
94
  - spec/spec_helper.rb
95
+ - spec/support/fake_page.rb
96
+ - spec/support/html_helpers.rb
72
97
  - style_cop.gemspec
73
98
  homepage: http://rubygems.org/gems/style_cop
74
99
  licenses:
@@ -80,17 +105,17 @@ require_paths:
80
105
  - lib
81
106
  required_ruby_version: !ruby/object:Gem::Requirement
82
107
  requirements:
83
- - - '>='
108
+ - - ">="
84
109
  - !ruby/object:Gem::Version
85
110
  version: '0'
86
111
  required_rubygems_version: !ruby/object:Gem::Requirement
87
112
  requirements:
88
- - - '>='
113
+ - - ">="
89
114
  - !ruby/object:Gem::Version
90
115
  version: '0'
91
116
  requirements: []
92
117
  rubyforge_project:
93
- rubygems_version: 2.1.10
118
+ rubygems_version: 2.2.2
94
119
  signing_key:
95
120
  specification_version: 4
96
121
  summary: Gem for testing style
data/Gemfile.lock DELETED
@@ -1,38 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- style_cop (0.0.1)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- coderay (1.1.0)
10
- diff-lcs (1.2.5)
11
- method_source (0.8.2)
12
- mini_portile (0.5.2)
13
- nokogiri (1.6.1)
14
- mini_portile (~> 0.5.0)
15
- pry (0.9.12.6)
16
- coderay (~> 1.0)
17
- method_source (~> 0.8)
18
- slop (~> 3.4)
19
- rspec (2.14.1)
20
- rspec-core (~> 2.14.0)
21
- rspec-expectations (~> 2.14.0)
22
- rspec-mocks (~> 2.14.0)
23
- rspec-core (2.14.8)
24
- rspec-expectations (2.14.5)
25
- diff-lcs (>= 1.1.3, < 2.0)
26
- rspec-mocks (2.14.6)
27
- slop (3.4.7)
28
- xpath (2.0.0)
29
- nokogiri (~> 1.3)
30
-
31
- PLATFORMS
32
- ruby
33
-
34
- DEPENDENCIES
35
- pry (~> 0.9.12.6)
36
- rspec (~> 2.14.0)
37
- style_cop!
38
- xpath (~> 2.0.0)
@@ -1,37 +0,0 @@
1
- module StyleCop
2
- class AssertStyle
3
- def initialize(selector, rules, test_context)
4
- @selector = selector
5
- @rules = rules
6
- @test_context = test_context
7
- end
8
-
9
- def has_correct_structure
10
- selector_present ? fulfills_all_rules : raise_error
11
- end
12
-
13
- private
14
-
15
- attr_reader :selector, :test_context, :rules
16
-
17
- def selector_present
18
- test_context.has_css?(selector)
19
- end
20
-
21
- def raise_error
22
- raise StandardError, "Selector: #{selector} is not present."
23
- end
24
-
25
- def fulfills_all_rules
26
- test_context.page.all(selector).each do |element|
27
- has(element)
28
- end
29
- end
30
-
31
- def has(element)
32
- rules.each do |node|
33
- test_context.expect(element).to test_context.have_selector(node)
34
- end
35
- end
36
- end
37
- end
@@ -1,23 +0,0 @@
1
- module StyleCop
2
- module PublicMethods
3
- def has_child(selector)
4
- RegisterStyle.add_rule("> #{selector}")
5
- end
6
-
7
- def has_nested_children(*args)
8
- rule = ""
9
- args.each do |arg|
10
- rule = "#{rule}> #{arg} "
11
- end
12
- RegisterStyle.add_rule(rule.strip)
13
- end
14
-
15
- def register_style_structure_for(selector, &block)
16
- block ? RegisterStyle.new(selector, &block) : (raise(StandardError, "No block given."))
17
- end
18
-
19
- def assert_style_structure_for(selector)
20
- AssertStyle.new(selector, RegisterStyle.rules, self).has_correct_structure
21
- end
22
- end
23
- end
@@ -1,17 +0,0 @@
1
- module StyleCop
2
- class RegisterStyle
3
- @@rules = []
4
-
5
- def initialize(selector, &block)
6
- yield
7
- end
8
-
9
- def self.rules
10
- @@rules
11
- end
12
-
13
- def self.add_rule(rule)
14
- @@rules << rule
15
- end
16
- end
17
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe StyleCop::AssertStyle do
4
- subject{ StyleCop::AssertStyle.new(selector, rules, test_context) }
5
- let(:selector) { '.selector' }
6
- let(:rules) { double('rules') }
7
- let(:test_context) { double('test_context') }
8
-
9
- describe "has_correct_structure" do
10
- before do
11
- allow(test_context).to receive(:has_css?) { has_selector }
12
- end
13
-
14
- context "selector present" do
15
- let(:has_selector) { true }
16
-
17
- let(:rule1) { double('rule1') }
18
- let(:rule2) { double('rule2') }
19
- let(:element1) { double('element1') }
20
- let(:element2) { double('element2') }
21
- let(:node1) { double('node1') }
22
- let(:node2) { double('node2') }
23
- let(:rules) { [rule1, rule2] }
24
-
25
- before do
26
- test_context.stub_chain(:page, :all) { [element1, element2] }
27
- end
28
-
29
- it "calls an expectation on elements" do
30
- expect(test_context).to receive(:expect).with(element1).twice { node1 }
31
- expect(test_context).to receive(:expect).with(element2).twice { node2 }
32
- allow(node1).to receive(:to)
33
- allow(node2).to receive(:to)
34
- expect(test_context).to receive(:have_selector).with(rule1).twice
35
- expect(test_context).to receive(:have_selector).with(rule2).twice
36
-
37
- subject.has_correct_structure
38
- end
39
- end
40
-
41
- context "selector not present" do
42
- let(:has_selector) { false }
43
-
44
- it "raises a StandardError" do
45
- expect { subject.has_correct_structure }.to raise_error { |error|
46
- expect(error.message).to eq "Selector: .selector is not present."
47
- error.should be_a(StandardError)
48
- }
49
- end
50
- end
51
- end
52
- end
@@ -1,60 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe StyleCop::PublicMethods do
4
- include StyleCop::PublicMethods
5
- let(:selector) {'.foo'}
6
-
7
- describe 'has_child' do
8
-
9
- it 'calls add_rule on RegisterStyle' do
10
- expect(StyleCop::RegisterStyle).to receive(:add_rule).with('> .foo')
11
- has_child selector
12
- end
13
- end
14
-
15
- describe 'has_nested_children' do
16
- let(:selector1) {'.foo'}
17
- let(:selector2) {'.bar'}
18
-
19
- it 'calls add_rule on RegisterStyle' do
20
- expect(StyleCop::RegisterStyle).to receive(:add_rule).with('> .foo > .bar')
21
- has_nested_children(selector1, selector2)
22
- end
23
- end
24
-
25
- describe 'register_style_structure_for' do
26
- let(:block) { lambda{} }
27
-
28
- context 'block is given' do
29
- it 'calls a new RegisterStyle' do
30
- expect(StyleCop::RegisterStyle).to receive(:new).with(selector, &block)
31
- register_style_structure_for(selector, &block)
32
- end
33
- end
34
-
35
- context 'no block is given' do
36
- it 'raises a no block error' do
37
- expect { register_style_structure_for(selector) }.to raise_error { |error|
38
- expect(error.message).to eq "No block given."
39
- error.should be_a(StandardError)
40
- }
41
- end
42
- end
43
- end
44
-
45
- describe 'assert_style_structure_for' do
46
- let(:rules) { double(:rules) }
47
- let(:assert_style_class) { double(:assert_style_class) }
48
-
49
- before do
50
- allow(StyleCop::RegisterStyle).to receive(:rules) { rules }
51
- end
52
-
53
- it "creates an AssertStyle object and calls has_correct_structure on it" do
54
- expect(StyleCop::AssertStyle).to receive(:new).with(selector, rules, self) { assert_style_class }
55
- expect(assert_style_class).to receive(:has_correct_structure)
56
-
57
- assert_style_structure_for(selector)
58
- end
59
- end
60
- end