style_cop 0.0.1 → 0.0.2

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.
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