fdlint 0.1.3 → 0.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -9
  3. data/Gemfile.lock +14 -4
  4. data/Rakefile +9 -85
  5. data/bin/fdlint +71 -8
  6. data/lib/fdlint/cli.rb +102 -0
  7. data/lib/{file_validator.rb → fdlint/file_validator.rb} +0 -0
  8. data/lib/fdlint/helper/code_type.rb +55 -0
  9. data/lib/fdlint/helper/file_reader.rb +19 -0
  10. data/lib/fdlint/helper/logger.rb +35 -0
  11. data/lib/fdlint/log_entry.rb +51 -0
  12. data/lib/fdlint/parser/base_parser.rb +151 -0
  13. data/lib/{css/parser.rb → fdlint/parser/css/css_parser.rb} +31 -28
  14. data/lib/{css → fdlint/parser/css}/struct.rb +5 -5
  15. data/lib/{encoding_error.rb → fdlint/parser/encoding_error.rb} +2 -2
  16. data/lib/{html/parser.rb → fdlint/parser/html/html_parser.rb} +26 -20
  17. data/lib/{html → fdlint/parser/html}/query.rb +0 -0
  18. data/lib/{html → fdlint/parser/html}/rule/check_tag_rule.rb +0 -0
  19. data/lib/{html → fdlint/parser/html}/struct.rb +82 -38
  20. data/lib/fdlint/parser/js/expr/expr.rb +71 -0
  21. data/lib/fdlint/parser/js/expr/left_hand.rb +65 -0
  22. data/lib/fdlint/parser/js/expr/operate.rb +94 -0
  23. data/lib/fdlint/parser/js/expr/primary.rb +168 -0
  24. data/lib/{js/parser.rb → fdlint/parser/js/js_parser.rb} +11 -9
  25. data/lib/fdlint/parser/js/stat/if.rb +27 -0
  26. data/lib/fdlint/parser/js/stat/iter.rb +88 -0
  27. data/lib/fdlint/parser/js/stat/stat.rb +120 -0
  28. data/lib/fdlint/parser/js/stat/switch.rb +67 -0
  29. data/lib/fdlint/parser/js/stat/try.rb +30 -0
  30. data/lib/fdlint/parser/js/stat/var.rb +42 -0
  31. data/lib/fdlint/parser/js/struct.rb +257 -0
  32. data/lib/fdlint/parser/node.rb +27 -0
  33. data/lib/fdlint/parser/parse_error.rb +10 -0
  34. data/lib/fdlint/parser/parser_visitable.rb +134 -0
  35. data/lib/{position_info.rb → fdlint/parser/position_info.rb} +12 -1
  36. data/lib/fdlint/parser.rb +3 -0
  37. data/lib/fdlint/printer/base_printer.rb +20 -0
  38. data/lib/fdlint/printer/console_printer.rb +80 -0
  39. data/lib/fdlint/printer/nocolor_printer.rb +29 -0
  40. data/lib/fdlint/printer/vim_printer.rb +21 -0
  41. data/lib/fdlint/printer.rb +1 -0
  42. data/lib/fdlint/rule/dsl.rb +83 -0
  43. data/lib/fdlint/rule/validation.rb +79 -0
  44. data/lib/fdlint/rule.rb +81 -0
  45. data/lib/fdlint/support/core/array.rb +5 -0
  46. data/lib/fdlint/support/core/file.rb +8 -0
  47. data/lib/fdlint/support/core/hash.rb +5 -0
  48. data/lib/fdlint/support/core/nil.rb +7 -0
  49. data/lib/fdlint/support/core/string.rb +7 -0
  50. data/lib/fdlint/support/core_ext.rb +5 -0
  51. data/lib/fdlint/validator.rb +102 -0
  52. data/lib/fdlint/version.rb +3 -0
  53. data/lib/fdlint.rb +5 -0
  54. data/rules.d/css.rule.rb +100 -0
  55. data/rules.d/filename.rule.rb +49 -0
  56. data/rules.d/html.rule.rb +169 -0
  57. data/rules.d/js.jquery.rule.rb +49 -0
  58. data/rules.d/js.rule.rb +205 -0
  59. data/test/default_test.rb +14 -0
  60. data/test/fixtures/js/scope-test.js +15 -2
  61. data/test/test_helper.rb +9 -0
  62. metadata +269 -221
  63. data/lib/base_parser.rb +0 -143
  64. data/lib/cmd_runner.rb +0 -145
  65. data/lib/context.rb +0 -31
  66. data/lib/css/reader.rb +0 -30
  67. data/lib/css/rule/check_compression_rule.rb +0 -48
  68. data/lib/css/rule/checklist.rb +0 -45
  69. data/lib/helper/code_type.rb +0 -50
  70. data/lib/helper/color_string.rb +0 -44
  71. data/lib/helper/file_reader.rb +0 -22
  72. data/lib/helper/strenc.rb +0 -65
  73. data/lib/js/expr/expr.rb +0 -66
  74. data/lib/js/expr/left_hand.rb +0 -63
  75. data/lib/js/expr/operate.rb +0 -92
  76. data/lib/js/expr/primary.rb +0 -166
  77. data/lib/js/rule/all.rb +0 -35
  78. data/lib/js/rule/checklist.rb +0 -41
  79. data/lib/js/rule/file_checker.rb +0 -42
  80. data/lib/js/rule/helper.rb +0 -96
  81. data/lib/js/rule/no_global.rb +0 -87
  82. data/lib/js/stat/if.rb +0 -25
  83. data/lib/js/stat/iter.rb +0 -85
  84. data/lib/js/stat/stat.rb +0 -117
  85. data/lib/js/stat/switch.rb +0 -65
  86. data/lib/js/stat/try.rb +0 -28
  87. data/lib/js/stat/var.rb +0 -40
  88. data/lib/js/struct.rb +0 -248
  89. data/lib/log_entry.rb +0 -49
  90. data/lib/node.rb +0 -28
  91. data/lib/parse_error.rb +0 -13
  92. data/lib/parser_visitable.rb +0 -138
  93. data/lib/printer/base_printer.rb +0 -24
  94. data/lib/printer/console_printer.rb +0 -66
  95. data/lib/printer/nocolor_printer.rb +0 -27
  96. data/lib/printer/vim_printer.rb +0 -19
  97. data/lib/rule.rb +0 -241
  98. data/lib/rule_helper.rb +0 -14
  99. data/lib/runner.rb +0 -225
  100. data/rules.d/css.rule +0 -127
  101. data/rules.d/html.dtd.rule +0 -22
  102. data/rules.d/html.prop.rule +0 -51
  103. data/rules.d/html.tag.rule +0 -136
  104. data/rules.d/js.file.rule +0 -13
  105. data/rules.d/js.jquery.rule +0 -56
  106. data/rules.d/js.mergefile.rule +0 -71
  107. data/rules.d/js.rule +0 -84
@@ -0,0 +1,257 @@
1
+ require_relative '../node'
2
+
3
+ module Fdlint
4
+
5
+ module Parser
6
+
7
+ module JS
8
+
9
+ Node = ::Fdlint::Parser::Node
10
+
11
+ class Element < Node
12
+ attr_reader :type, :left, :right
13
+
14
+ def initialize(type, left = nil, right = nil, position = nil)
15
+ @type, @left, @right, @position = type, left, right, position
16
+ end
17
+
18
+ def text
19
+ "(#{type},#{left},#{right})"
20
+ end
21
+
22
+ def position
23
+ @position ? @position :
24
+ left ? left.position :
25
+ right ? right.position : nil
26
+ end
27
+
28
+ def contains?(target)
29
+ return true if target == @type
30
+ left && left.respond_to?(:contains?) && left.contains?(target) or
31
+ right && right.respond_to?(:contains?) && right.contains?(target)
32
+ end
33
+
34
+ end
35
+
36
+ class Elements < Node
37
+ attr_reader :elements, :type
38
+
39
+ def initialize(elements, position = nil)
40
+ @elements, @position = elements, position
41
+ @type = 'elements'
42
+ end
43
+
44
+ def text
45
+ "[#{elements.collect(&:text).join(',')}]"
46
+ end
47
+
48
+ def position
49
+ @position ? @position :
50
+ elements.empty? ? nil : elements[0].position
51
+ end
52
+
53
+ def method_missing(m, *args, &block)
54
+ @elements.send m, *args, &block
55
+ end
56
+
57
+ def contains?( target )
58
+ @elements.any? {|elm| elm.contains? target }
59
+ end
60
+
61
+ alias :contain? :contains?
62
+ end
63
+
64
+ # The whole program element
65
+ # Javascript files are first parsed into programs.
66
+ class Program < Element
67
+ alias :elements :left
68
+
69
+ def initialize(elements)
70
+ super 'program', elements
71
+ end
72
+
73
+ end
74
+
75
+ # Function declaraion
76
+ # key word 'function' parsed as FunctionDeclaraion
77
+ class FunctionDeclaraion < Element
78
+ attr_reader :body
79
+ alias :name :left
80
+ alias :parameters :right
81
+
82
+ def initialize(name, parameters, body, pos)
83
+ super 'function', name, parameters, pos
84
+ @body = body
85
+ end
86
+ end
87
+
88
+ class Statement < Element
89
+
90
+ def end_with_semicolon=(end_with_semicolon)
91
+ @end_with_semicolon = !!end_with_semicolon
92
+ end
93
+
94
+ def end_with_semicolon?
95
+ !!@end_with_semicolon
96
+ end
97
+
98
+ end
99
+
100
+ class VarStatement < Statement
101
+ alias :declarations :left
102
+
103
+ def initialize(declarations, position)
104
+ super 'var', declarations, nil, position
105
+ end
106
+ end
107
+
108
+ class BlockStatement < Statement
109
+ alias :elements :left
110
+
111
+ def initialize(elements, pos)
112
+ super 'block', elements, nil, pos
113
+ end
114
+ end
115
+
116
+ class IfStatement < Statement
117
+ attr_reader :false_part
118
+ alias :condition :left
119
+ alias :true_part :right
120
+
121
+ def initialize(condition, true_part, false_part, position)
122
+ super 'if', condition, true_part, position
123
+ @false_part = false_part
124
+ end
125
+ end
126
+
127
+ class SwitchStatement < Statement
128
+ alias :expression :left
129
+ alias :case_block :right
130
+
131
+ def initialize(expression, case_block, position)
132
+ super 'switch', expression, case_block, position
133
+ end
134
+ end
135
+
136
+ class CaseBlockStatement < Statement
137
+ attr_reader :bottom_case_clauses
138
+ alias :case_clauses :left
139
+ alias :default_clause :right
140
+
141
+ def initialize(case_clauses, default_clause, bottom_case_clauses, position)
142
+ super 'caseblock', case_clauses, default_clause, position
143
+ @bottom_case_clauses = bottom_case_clauses
144
+ end
145
+ end
146
+
147
+ class DowhileStatement < Statement
148
+ alias :body :left
149
+ alias :condition :right
150
+
151
+ def initialize(body, condition, pos)
152
+ super 'dowhile', body, condition, pos
153
+ end
154
+ end
155
+
156
+ class WhileStatement < Statement
157
+ alias :condition :left
158
+ alias :body :right
159
+
160
+ def initialize(condition, body, pos)
161
+ super 'while', condition, body, pos
162
+ end
163
+ end
164
+
165
+ class ForStatement < Statement
166
+ alias :condition :left
167
+ alias :body :right
168
+
169
+ def initialize(condition, body, pos)
170
+ super 'for', condition, body, pos
171
+ end
172
+ end
173
+
174
+ class ForConditionElement < Element
175
+ attr_reader :third
176
+ alias :first :left
177
+ alias :second :right
178
+
179
+ def initialize(type, first, second, third, pos)
180
+ super type, first, second
181
+ @third = third
182
+ end
183
+
184
+ end
185
+
186
+ class TryStatement < Statement
187
+ attr_reader :finally_part
188
+ alias :try_part :left
189
+ alias :catch_part :right
190
+
191
+ def initialize(try_part, catch_part, finally_part, pos)
192
+ super 'try', try_part, catch_part, pos
193
+ @finally_part = finally_part
194
+ end
195
+ end
196
+
197
+ class ExpressionStatement < Statement
198
+ alias :expression :left
199
+
200
+ def initialize(expression)
201
+ super 'expression', expression
202
+ end
203
+ end
204
+
205
+ class Expression < Element
206
+ def left_hand?
207
+ @left_hand || false
208
+ end
209
+
210
+ def left_hand=(left_hand)
211
+ @left_hand = left_hand
212
+ end
213
+ end
214
+
215
+ class PrimaryExpression < Expression
216
+
217
+ def initialize(type, expr, position = nil)
218
+ super type, expr, nil, position
219
+ end
220
+
221
+ def text
222
+ node.text
223
+ end
224
+
225
+ def node
226
+ left
227
+ end
228
+ end
229
+
230
+ class ConditionExpression < Expression
231
+ attr_reader :condition
232
+
233
+ def initialize(condition, left, right)
234
+ super '?:', left, right, condition.position
235
+ @condition = condition
236
+ end
237
+
238
+ def text
239
+ "(#{type},#{condition},#{left},#{right})"
240
+ end
241
+
242
+ end
243
+
244
+ class FunctionExpression < Expression
245
+ attr_reader :body
246
+ alias :name :left
247
+ alias :parameters :right
248
+
249
+ def initialize(func)
250
+ super 'function', func.name, func.parameters, func.position
251
+ @body = func.body
252
+ end
253
+ end
254
+
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,27 @@
1
+ module Fdlint
2
+ module Parser
3
+
4
+ class Node
5
+
6
+ attr_accessor :text, :position
7
+
8
+ def initialize(text = '', position = nil)
9
+ if text.is_a? Node
10
+ @text, @position = text.text, text.position
11
+ else
12
+ @text, @position = (text || '').strip, position
13
+ end
14
+ end
15
+
16
+ def =~(other)
17
+ text =~ other
18
+ end
19
+
20
+ def to_s
21
+ text
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ class Fdlint::Parser::ParseError < RuntimeError
2
+
3
+ attr_reader :position
4
+
5
+ def initialize(msg = nil, position = nil)
6
+ super msg
7
+ @position = position
8
+ end
9
+
10
+ end
@@ -0,0 +1,134 @@
1
+ require 'fdlint/log_entry'
2
+
3
+ module Fdlint
4
+
5
+ module Parser
6
+
7
+ class VisitResult < LogEntry
8
+
9
+ attr_reader :node
10
+
11
+ def initialize(node, message, level)
12
+ @node = node
13
+ pos = node.position || Position.new(0, 0, 0)
14
+ super message, level, pos.row, pos.column
15
+ end
16
+ end
17
+
18
+
19
+ module ParserVisitable
20
+
21
+ def self.included(klass)
22
+ klass.public_instance_methods(true).grep(/^parse_/) do |method|
23
+ wrap(klass, method)
24
+ end
25
+
26
+ def klass.method_added(method)
27
+ unless @flag
28
+ @flag = true
29
+ case method.to_s
30
+ when /^parse_/
31
+ ParserVisitable.wrap(self, method)
32
+ end
33
+ @flag = false
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.wrap(klass, method)
39
+ method = method.to_s
40
+
41
+ klass.instance_eval do
42
+
43
+ old_method = "#{method}_without_visit"
44
+ name = method.sub /^parse_/, ''
45
+
46
+ alias_method old_method, method
47
+
48
+ define_method(method) do |*args, &block|
49
+ before name, *args
50
+ node = self.send(old_method, *args, &block)
51
+ node && visit(name, node)
52
+ node
53
+ end
54
+ end
55
+ end
56
+
57
+ def parse_no_throw
58
+ root = []
59
+ begin
60
+ root = self.parse
61
+ rescue ParseError => e
62
+ results << LogEntry.new(e.to_s, :fatal, e.position.row, e.position.column)
63
+ end
64
+ root
65
+ end
66
+
67
+ # Public: Add visitor hooks
68
+ #
69
+ # visitors - The visitors array. The members in the
70
+ # Array must be presented in this format:
71
+ # `[ scope, proc ]`
72
+ # where scope is the name of target node
73
+ # scope; proc is the handler.
74
+ #
75
+ # Returns Parser's visitors
76
+ def add_visitors(visitors)
77
+ visitors.each do |target, visitor|
78
+ add_visitor target, visitor
79
+ end
80
+ self.visitors
81
+ end
82
+
83
+ # Public: Add visitor hook
84
+ #
85
+ # target - The target to watch. For example, when
86
+ # target is 'selector', then the visitor
87
+ # will be invoked after <code>parse_select
88
+ # </code> invoked by parser.
89
+ # visitor - The handler proc. It will be yielded
90
+ # with these arguments:
91
+ # * node: current node scope, same as
92
+ # `target` here
93
+ # * source: the entire file source
94
+ #
95
+ # Returns the visitors for the scope
96
+ def add_visitor(scope, visitor)
97
+ cache = visitors[scope.to_s] ||= []
98
+ cache << visitor
99
+ end
100
+
101
+ def visitors
102
+ @visitors ||= {}
103
+ end
104
+
105
+ def results
106
+ @results ||= []
107
+ end
108
+
109
+ private
110
+
111
+ def visit(name, node)
112
+ walk(name, node) do |result|
113
+ results << result
114
+ end
115
+ end
116
+
117
+ def before(name)
118
+ walk 'before_parse_' << name, nil do |result|
119
+ results << result
120
+ end
121
+ end
122
+
123
+ def walk(name, node, &block)
124
+ visitors = self.visitors[name.to_s]
125
+ visitors && visitors.each do |visitor|
126
+ result = visitor.call node, source, self
127
+ yield result if result && block_given?
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+ end
@@ -1,10 +1,14 @@
1
- module XRay
1
+ module Fdlint::Parser
2
2
 
3
3
  Position = Struct.new(:pos, :row, :column)
4
4
  class Position
5
5
  def to_s
6
6
  "[#{row},#{column}]"
7
7
  end
8
+
9
+ def inspect
10
+ "[#{pos}, #{row}:#{column}]"
11
+ end
8
12
  end
9
13
 
10
14
  class PositionInfo
@@ -22,6 +26,13 @@ module XRay
22
26
  @len = lines.length
23
27
  end
24
28
 
29
+ # Public: Turn given number position index into a
30
+ # position object which contains the
31
+ # column and row index info
32
+ #
33
+ # pos - position index of the source string
34
+ #
35
+ # Returns the position object
25
36
  def locate(pos)
26
37
  if @row && pos >= @lines[@row -1] && pos < @lines[@row]
27
38
  row = @row
@@ -0,0 +1,3 @@
1
+ require 'fdlint/parser/base_parser'
2
+ require 'fdlint/parser/parser_visitable'
3
+ require 'fdlint/parser/encoding_error'
@@ -0,0 +1,20 @@
1
+ module Fdlint
2
+
3
+ module Printer
4
+
5
+ class BasePrinter
6
+
7
+ def initialize( opt={} )
8
+ @opt= opt
9
+ end
10
+
11
+ attr_accessor :file, :source, :results
12
+
13
+ def print( file, source, results )
14
+ @file, @source, @results = file, source, results || []
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,80 @@
1
+ require 'colored'
2
+
3
+ module Fdlint
4
+
5
+ module Printer
6
+
7
+ class ConsolePrinter < BasePrinter
8
+
9
+ def print( file, source, results )
10
+
11
+ super
12
+
13
+ if source
14
+ print_with_source
15
+ else
16
+ if @results && @results.empty?
17
+ puts "[OK] ".green << file.to_s
18
+ else
19
+ puts "[EE] ".red << file.to_s
20
+
21
+ @results.each do |r|
22
+ print_log_entry r
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def print_with_source
29
+ if @results.empty?
30
+ puts "[OK] ".green << file.to_s
31
+ else
32
+ puts "[EE] ".red << file.to_s
33
+
34
+ @results.each do |r|
35
+ print_log_entry r
36
+ end
37
+ end
38
+
39
+
40
+ end
41
+
42
+ def print_log_entry( entry )
43
+ if entry.row && entry.row > 0
44
+ col = entry.column - 1
45
+ row = entry.row - 1
46
+ left = col - 50
47
+ right = col + 50
48
+ left = 0 if left < 0
49
+ indent = ' ' * ( col - left )
50
+
51
+ puts " #{log_text entry}\n"
52
+ puts " #{source.lines[row][left..right].gsub(/\t/, ' ')}"
53
+ puts " #{indent}^"
54
+ else
55
+ puts " #{log_text entry}\n"
56
+ end
57
+ end
58
+
59
+
60
+ def log_text( entry )
61
+ level = entry.level.to_s.upcase.ljust(5)
62
+ t = if entry.warn?
63
+ level.yellow
64
+ elsif entry.fatal?
65
+ level.white_on_red
66
+ elsif entry.error?
67
+ level.red
68
+ else
69
+ level
70
+ end
71
+ if entry.row
72
+ "[%s] %s %s" % [t, entry.pos, entry.message]
73
+ else
74
+ "[%s] %s" % [t, entry.message]
75
+ end
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,29 @@
1
+ module Fdlint
2
+
3
+ module Printer
4
+
5
+ class NoColorPrinter < BasePrinter
6
+
7
+ def print( file, source, results )
8
+
9
+ super
10
+
11
+ if results.empty?
12
+ puts "[OK] #{file}"
13
+ else
14
+ prf = @opt[:prefix]
15
+ suf = @opt[:suffix]
16
+ out = @opt[:out]
17
+
18
+ puts "[EE] #{file}"
19
+
20
+ results.each do |r|
21
+ puts "#{prf}#{r}#{suf}"
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ module Fdlint
2
+
3
+ module Printer
4
+
5
+ class VimPrinter < BasePrinter
6
+
7
+ def print( file, source, results )
8
+ prf = ( file || '-' ).dup.utf8!
9
+ results.each do |r|
10
+ if r.row
11
+ puts "%s:[%s]:%d:%d:%s" % [prf, r.level, r.row, r.column, r.message]
12
+ else
13
+ puts "%s:[%s]:%d:%d:%s" % [prf, r.level, 0, 0, r.message]
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1 @@
1
+ require 'fdlint/printer/base_printer'
@@ -0,0 +1,83 @@
1
+ module Fdlint; module Rule
2
+
3
+ module DSL
4
+
5
+ extend self
6
+
7
+ # Public: Extend target class
8
+ #
9
+ # target - An String or Class object
10
+ def helpers( target, &block )
11
+ if target.is_a? String
12
+ target = Object.const_get target.capitalize
13
+ end
14
+ target.class_eval &block
15
+ end
16
+
17
+ def rules_for( *syntaxes, &block )
18
+ @syntaxes = syntaxes.map(&:intern)
19
+ yield if block_given?
20
+ end
21
+
22
+ def css_rules( &block )
23
+ rules_for( :css, &block )
24
+ end
25
+
26
+ def html_rules( &block )
27
+ rules_for( :html, &block )
28
+ end
29
+
30
+ def js_rules( &block )
31
+ rules_for( :js, &block )
32
+ end
33
+
34
+ def group( grp, &block )
35
+ @group = grp
36
+ yield if block_given?
37
+ end
38
+
39
+ def desc( description=nil )
40
+ @desc = description
41
+ end
42
+
43
+ def uri( u )
44
+ @uri = u
45
+ end
46
+
47
+ def check( node, &block )
48
+ @scope = node.intern
49
+ if block && block.arity > 0
50
+ rule &block
51
+ else
52
+ yield if block_given?
53
+ end
54
+ end
55
+
56
+ alias_method :review, :check
57
+
58
+ def rule( &block )
59
+ @syntaxes.each do |syntax|
60
+ ::Fdlint::Rule.add syntax, @scope, {
61
+ :block => block,
62
+ :desc => @desc,
63
+ :uri => @uri
64
+ }
65
+ end
66
+
67
+ @desc = nil
68
+ @uri = nil
69
+ end
70
+
71
+ def before( element, &block )
72
+ @scope = :"before_parse_#{element}"
73
+ rule &block
74
+ end
75
+
76
+ def after( element, &block )
77
+ @scope = element.intern
78
+ rule &block
79
+ end
80
+
81
+ end
82
+
83
+ end; end;