outlaw 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,35 +1,108 @@
1
1
  #Outlaw
2
2
 
3
3
  ##Keep bad code out of your projects. Your idea of bad code, no one elses.
4
+ ##Because good documentation should be executable.
5
+
6
+ ###NOTE: Outlaw can evaluate any version ruby code, *BUT* it runs on only 1.9 -- set your system ruby to 1.9 to use
4
7
 
5
8
  ### Part of MendicantUniversity.org S10 class, personal project.
6
- From the included outlawed.rb example file for custom rule definition:
7
9
 
8
- module Outlaw
9
- outlaw "@@", "Class variables are evil"
10
- outlaw "protected", "use private or public, protected is silly in ruby"
11
- outlaw "module :token end", "nest modules to avoid empty module declarations"
12
- outlaw "eval", "never eval, rarely class_eval or instance_eval, but never eval"
13
- end
10
+ The current version of outlaw takes a user provided configuration file
11
+ (currently named simply '.outlawed' in the project directory or user's home
12
+ directory) and parses a series of method calls to the outlaw method (defined
13
+ within the Outlaw module namespace, but module_eval'd so you don't need to
14
+ namespace the file). You can also define constants in your .outlawed file as
15
+ collections of strings for use in your rules, but that will be addressed below.
16
+
17
+ Each call to the outlaw method consists of two string arguments, the first an
18
+ anti-pattern you wish to prohibit usage of in one or more projects, and the
19
+ second an explanation to be provided when the anti-pattern is detected.
20
+
21
+ ### Syntax for rule creation:
22
+
23
+ Some examples are included in the .outlawed.example file for reference:
24
+
25
+ outlaw "@@", "Class variables are evil"
26
+
27
+ outlaw "protected", "use private or public, protected
28
+ is silly in ruby"
29
+
30
+ outlaw "eval", "never eval, rarely class_eval or
31
+ instance_eval, but never eval"
32
+
33
+ outlaw "module :token end", "nest modules to avoid empty module
34
+ declarations"
35
+
36
+ outlaw "class :symbol < :core_class", "core classes implemented in c,
37
+ can cause bad mojo"
38
+
39
+ outlaw :trailing_whitespace
40
+
41
+
42
+ The first three examples are actual ruby keywords and features being outlawed
43
+ and may not require much explanation except to indicate that they are detected
44
+ via regular expression matches constructed from the strings, and attempt to use
45
+ word boundaries intelligently so that eval is detected but not module_eval.
46
+
47
+ The bottom two examples above use ruby symbols as standin variable or
48
+ parameter names for identifiers that are matched at runtime with local
49
+ variables, instance variables, class names and constants that may appear
50
+ within the ruby program being analyzed. Here, :symbol can be any ruby symbol
51
+ if it appears only once, though if used multiple times it will only match the
52
+ the same identifier on subsequent usage. :core_class as used above is a
53
+ special case where Outlaw has internally defined a constant called CORE_CLASS
54
+ as a collection of string objects each containing the name of one of ruby's
55
+ core classes. You can define your own similar collections in the .outlawed
56
+ file (to be loaded from an external data file preferably, if more than a few
57
+ values) and then reference CONST_NAME as :const_name in your outlaw anti-
58
+ patterns as above. Presently mutliple references to the same collection
59
+ are independent, but if there is interest special handling could be added to
60
+ also match specific instances of a collection much like the symbol handling.
61
+
62
+ The last one is a custom rule that calls a method defined on the Outlaw
63
+ module called 'trailing_whitespace' which returns a Rule object. Any
64
+ such new methods may be defined in the .outlawed file (since it is
65
+ module_eval'd into the outlaw namespace) and then outawed the same way.
66
+
67
+
68
+ Outlaw currently ignores whitespace, parentheses and new lines, though I have
69
+ ideas to change this behavior dynamically in certain rules if desired.
70
+
71
+ Execute outlaw on your project from the root directory by simply entering
72
+ "outlaw" into your shell, or specify another directory to run
73
+ on with "outlaw /path/to/dir"
74
+
75
+ Before using outlaw in a project you should create a .outlawed file which
76
+ Outlaw will read rules from.
14
77
 
15
- ### Proposed syntax for DSL:
78
+ It comes with an example file (.outlawed.example) which is included in the
79
+ gem and will be loaded if no .outlawed file is found in current directory or
80
+ home directory, and will warn you to provide a real file (and provide
81
+ location of the sample file in your system from the gem installation).
16
82
 
17
- A defined collection exists for core classes, such that
83
+ ###Planned features (unimplemented):
84
+ *Customize sensitivty , for instance whitespace is currently ignored, but
85
+ could enforce style conventions with some whitespace sensitive rules.
86
+ Also ignores parens, which might be required or prohibited in some
87
+ context.
88
+ *Specify AST-nodes of interest, and within them allow arbitrary amounts of
89
+ code with a :disjoint_code_seperator token.
18
90
 
19
- outlaw "class :symbol < :core_class",
20
- "core classes implemented in c, can cause bad mojo"
91
+ This should allow, for instance, something like the following, which is not
92
+ currently possible to outlaw in a useful way:
21
93
 
22
- will outlaw subclassing from any core class
94
+ outlaw ":conditional_branch
95
+ unless
96
+ :disjoint_code_seperator
97
+ else",
98
+ "If you write unless else and think it makes sense then you are a
99
+ cylon"
23
100
 
101
+ *Integrate Rails Best Practices gem, Reek gem, and perhaps others, so that individual issue
102
+ detections they provide can be added as rules in the outlawed file while
103
+ ignoring/not running other detection routines.
24
104
 
25
- Users can extend new defined collections and by creating new constants
26
- defined as arrays of variable names to match in example code the same
27
- way :core_class is used above
105
+ *Automate optional integration with rake task and/or githooks for
106
+ enforcement/notification of rules in a project.
28
107
 
29
- Disjoin code segments can be provided as a single example (assuming they
30
- occur in the same file) by inserting a :disjoint_code_seperator token in
31
- the outlawed sample definition. I don't have a good use case for this
32
- at present though, and since it will be difficult to handle disjoint
33
- code across different files this may not be worthwhile... but similar
34
- special case symbol meanings may be useful, and suggestions or examples
35
- are welcome.
108
+ *Specify classes of rules, such as log, warn and prevent for differing behavior regarding violations at runtime.
data/bin/outlaw CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "outlaw"
3
+ require_relative "../lib/outlaw"
4
4
  if File.exists?(Dir.pwd + '/.outlawed')
5
- load Dir.pwd + "/.outlawed"
5
+ File.open(Dir.pwd + "/.outlawed") {|f| Outlaw.module_eval(f.read)}
6
6
  elsif File.exists?(Dir.home + '/.outlawed')
7
- load Dir.home + '/.outlawed'
7
+ File.open(Dir.home + '/.outlawed') {|f| Outlaw.module_eval(f.read)}
8
8
  else
9
9
  puts "
10
10
  ***NOTICE:***
@@ -14,7 +14,8 @@ else
14
14
  at pwd first for ./outlawed and then at ~/.outlawed and defaults to example
15
15
  if neither is found\n\n"
16
16
 
17
- load File.dirname(File.dirname(`gem which outlaw`.chop)) + '/examples/.outlawed.example'
17
+ File.open(File.dirname(File.dirname(`gem which outlaw`.chop)) +
18
+ '/examples/.outlawed.example') {|f| Outlaw.module_eval(f.read)}
18
19
  end
19
20
 
20
21
  puts Outlaw.enforce(ARGV[0] ? ARGV[0] : ".")
@@ -1,5 +1,6 @@
1
1
  outlaw "@@", "class variables are evil"
2
2
  outlaw "protected", "use private or public, protected is silly in ruby"
3
3
  outlaw "module :token end", "nest modules to avoid empty module declarations"
4
- outlaw "eval", "never eval, rarely class_eval or instance_eval, but never eval"
5
- outlaw "class :symbol < :core_class", "core classes implemented in c, can cause bad mojo"
4
+ outlaw "eval", "never eval, rarely class_eval or instance_eval, but never eval"
5
+ outlaw "class :symbol < :core_class", "core classes implemented in c, can cause bad mojo"
6
+ outlaw :trailing_whitespace
@@ -1,20 +1,34 @@
1
1
  require 'ripper'
2
- require_relative 'outlaw/law_dsl'
2
+ require_relative 'outlaw/law_parser'
3
3
  require_relative 'outlaw/enforcement'
4
4
  require_relative 'outlaw/rule'
5
+ require_relative 'outlaw/rule_methods'
6
+
5
7
 
6
- def outlaw(restriction, message)
7
- law = Outlaw::LawDSL.parse(restriction, message)
8
- Outlaw::Enforcement.add(law)
9
- end
10
8
 
11
9
  module Outlaw
12
- def self.enforce(dir=".")
10
+ extend self
11
+ attr_accessor :ignore_types, :param_types
12
+
13
+ def outlaw(pattern, message=nil)
14
+ if pattern.kind_of?(String)
15
+ rule = Rule.new(pattern, message)
16
+ Outlaw::Enforcement.add(rule)
17
+ else
18
+ Outlaw::Enforcement.add(self.send(pattern))
19
+ end
20
+ end
21
+
22
+ def enforce(dir=".")
13
23
  Outlaw::Enforcement.process_directory(dir)
14
24
  end
15
- PARAM_TYPES = [:on_const, :on_ident, :on_ivar, :on_cvar]
16
- IGNORE_TYPES = [:on_sp, :on_nl, :on_ignored_nl, :on_rparen, :on_lparen]
17
- SPECIAL_CASES = [:disjoint_code_seperator] #need to work on naming here
18
- CORE_CLASSES_FILE = File.expand_path("../../data/core_classes.txt", __FILE__)
19
- CORE_CLASS = File.readlines(CORE_CLASSES_FILE).map &:chomp
25
+ #these come from ripper's Lexer
26
+ self.param_types = [:on_const, :on_ident, :on_ivar, :on_cvar]
27
+ self.ignore_types = [:on_sp, :on_nl, :on_ignored_nl, :on_rparen, :on_lparen]
28
+ WHITESPACE = [:on_sp, :on_nl, :on_ignored_nl]
29
+ VERTICAL_WHITESPACE = [:on_nl, :on_ignored_nl]
30
+ SPECIAL_CASES = [:whitespace_sensitive, :vertical_whitespace_sensitive]
31
+
32
+ CORE_CLASSES_FILE = File.expand_path("../../data/core_classes.txt", __FILE__)
33
+ CORE_CLASS = File.readlines(CORE_CLASSES_FILE).map &:chomp
20
34
  end
@@ -1,10 +1,10 @@
1
1
  module Outlaw
2
2
  class Enforcement
3
3
  class << self
4
- attr_reader :laws
5
- def add(law)
6
- @laws ||= []
7
- @laws << law
4
+ attr_reader :rules
5
+ def add(rule)
6
+ @rules ||= []
7
+ @rules << rule
8
8
  end
9
9
 
10
10
  def process_directory(path)
@@ -21,10 +21,10 @@ module Outlaw
21
21
  def handle(file)
22
22
  if file.match(/.rb$/)
23
23
  text = File.open(file) {|f| f.read}
24
- laws.each do |law|
25
- if law.call(text)
26
- puts "Outlaw Violation in file: #{file}\nRestriction:" +
27
- "#{law.restriction}\n\n#{law.message}"
24
+ rules.each do |rule|
25
+ if rule.violation?(text)
26
+ puts "Outlaw Violation in file: #{file}\nRestriction:\n" +
27
+ "#{rule.pattern}\n#{rule.message}\n\n"
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,73 @@
1
+ module Outlaw
2
+ module LawParser
3
+ extend self
4
+ def parse(restriction, rule)
5
+ tokens = restriction.split
6
+ parsed_restriction = []
7
+ tokens.each do |token|
8
+ case
9
+ when special_case?(string_to_sym(token))
10
+ handle_special(token, rule)
11
+ when multipart?(token) #this handles multi-token literals, Const.new etc
12
+ parsed_restriction += Ripper.lex(token)
13
+ .reduce([]){|array, tkn|
14
+ array << token_type_regex(tkn) }
15
+ when defined_collection?(token)
16
+ parsed_restriction << Outlaw.const_get(string_to_sym(token.upcase))
17
+ when parameter?(token)
18
+ parsed_restriction << string_to_sym(token)
19
+ else
20
+ parsed_restriction += build_regex(token)
21
+ end
22
+ end
23
+ build_block(parsed_restriction)
24
+ end
25
+
26
+ private
27
+
28
+ def handle_special(token, rule)
29
+ rule.modifications ||= []
30
+ rule.modifications << string_to_sym(token)
31
+ end
32
+
33
+ def special_case?(token)
34
+ SPECIAL_CASES.include?(token)
35
+ end
36
+
37
+ def token_type_regex(token)
38
+ /#{token[2]}/
39
+ end
40
+
41
+ def parameter?(token)
42
+ token[0].chr == ':'
43
+ end
44
+
45
+ def defined_collection?(token)
46
+ parameter?(token) && Outlaw.const_defined?(string_to_sym(token.upcase))
47
+ end
48
+
49
+ def string_to_sym(str)
50
+ str[1..-1].to_sym
51
+ end
52
+
53
+ def build_regex(token)
54
+ #fully expect this hack to come back & haunt me, but passes curr. examples
55
+ [/\A#{token}/]
56
+ end
57
+
58
+ def multipart?(token)
59
+ !parameter?(token) && Ripper.lex(token).count > 1
60
+ end
61
+
62
+ def build_block(pattern)
63
+ ->(file) do
64
+ program = Ripper.tokenize(file)
65
+ program.each_with_index do |token, index|
66
+ next unless token.match(pattern.first)
67
+ return true if Rule.test(program, index, pattern)
68
+ end
69
+ return false
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,18 +1,50 @@
1
1
  module Outlaw
2
2
  class Rule
3
- NoDetectionBlockProvided = Class.new(StandardError)
4
- attr_reader :message, :restriction
5
- def initialize(message, restriction, &detection_block)
6
- raise NoDetectionBlockProvided unless detection_block
7
- @message = message
8
- @restriction = restriction
3
+ attr_reader :message, :pattern, :detection_block
4
+ attr_accessor :modifications
5
+ def initialize(pattern, message=nil, &detection_block)
6
+ @pattern = pattern
7
+ @message = message ? message : "Don't do this: #{pattern}"
9
8
  @detection_block = detection_block
10
9
  end
11
10
 
12
- def call(code)
13
- @detection_block.call(code)
11
+ def violation?(code)
12
+ @detection_block = LawParser.parse(pattern, self) if detection_block.nil?
13
+ detect_violation(code)
14
14
  end
15
15
 
16
+ private
17
+
18
+ def detect_violation(code)
19
+ defaults = apply_modifications
20
+ result = detection_block.call(code)
21
+ apply_modifications(defaults)
22
+ result
23
+ end
24
+
25
+ def apply_modifications(restore=nil)
26
+ return nil if modifications.nil? && restore.nil?
27
+ default_ignores = Outlaw.ignore_types.clone
28
+ default_params = Outlaw.param_types.clone
29
+ if modifications.include?(:whitespace_sensitive)
30
+ WHITESPACE.each do |ws|
31
+ Outlaw.ignore_types.delete(ws)
32
+ Outlaw.param_types << ws
33
+ end
34
+ end
35
+ if modifications.include?(:vertical_whitespace_sensitive)
36
+ VERTICAL_WHITESPACE.each do |ws|
37
+ Outlaw.ignore_types.delete(ws)
38
+ Outlaw.param_types << ws
39
+ end
40
+ end
41
+ Outlaw.ignore_types = restore.first if restore
42
+ Outlaw.param_types = restore.last if restore
43
+ [default_ignores, default_params]
44
+ end
45
+
46
+ public
47
+
16
48
  class << self
17
49
  def test(program, start_index, pattern)
18
50
  pattern_index = 0
@@ -20,8 +52,8 @@ module Outlaw
20
52
  start_index.upto(program.length) do |index|
21
53
  code = program[index]
22
54
  part = pattern[pattern_index]
23
-
24
- next if IGNORE_TYPES.include? token_type(code)
55
+ return false if code.nil?
56
+ next if Outlaw.ignore_types.include?(token_type(code))
25
57
  return false unless match_token?(code, part, params[part])
26
58
  pattern_index +=1
27
59
  return true if pattern_index >= pattern.length
@@ -64,7 +96,7 @@ module Outlaw
64
96
 
65
97
  def param_type_equal(lex, param)
66
98
  #for now just check if it's a variable type, not kw, ws or other token
67
- PARAM_TYPES.include? lex
99
+ Outlaw.param_types.include? lex
68
100
  end
69
101
 
70
102
  def token_type(code)
@@ -0,0 +1,8 @@
1
+ module Outlaw
2
+ def trailing_whitespace
3
+ Rule.new("Trailing whitespace",
4
+ "Trailing whitespace is ugly and can mess up version history") do |file|
5
+ file.match(/ \n/)
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module Outlaw
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -1,59 +1,61 @@
1
1
  require_relative 'test_helper'
2
2
 
3
3
  module Outlaw
4
- describe LawDSL do
4
+ describe LawParser do
5
5
  it "returns a Rule which is called on code and returns true or false" do
6
6
  end
7
7
 
8
8
  before do
9
- @okay_file = <<CODE
10
- class Whatever < Set
11
- def okaything(here)
12
- @here = here
13
- end
14
- end
15
-
16
- module WithContent
17
- def sumthin
18
- class_eval('1 + 1')
19
- end
20
- end
21
- CODE
22
-
9
+ @okay_file = %{
10
+ class Whatever < Set
11
+ def okaything(here)
12
+ @here = here
13
+ end
14
+ end
15
+
16
+ module WithContent
17
+ def sumthin
18
+ class_eval('1 + 1')
19
+ end
20
+
21
+ def okishthing
22
+ end
23
+ end
24
+ }
23
25
  end
24
26
 
25
27
 
26
28
 
27
29
  it "correctly builds rule for class var" do
28
30
  code1 = "@@"
29
- rule1 = LawDSL.parse(code1)
31
+ rule1 = Rule.new(code1)
30
32
 
31
- class_var_file = <<CODE
32
- def badthing(here)
33
- @@here = here
34
- end
35
- CODE
33
+ class_var_file = %{
34
+ def badthing(here)
35
+ @@here = here
36
+ end
37
+ }
36
38
 
37
- class_result = rule1.call(class_var_file)
38
- result1a = rule1.call(@okay_file)
39
+ class_result = rule1.violation?(class_var_file)
40
+ result1a = rule1.violation?(@okay_file)
39
41
  class_result .must_equal true
40
42
  end
41
43
 
42
44
  it "correctly builds rule for protected" do
43
45
  code2 = "protected"
44
- rule2 = LawDSL.parse(code2)
46
+ rule2 = Rule.new(code2)
45
47
 
46
- protected_file = <<CODE
47
- class Whatever
48
- protected
49
- def not_really
50
- :false
51
- end
52
- end
53
- CODE
48
+ protected_file = %{
49
+ class Whatever
50
+ protected
51
+ def not_really
52
+ :false
53
+ end
54
+ end
55
+ }
54
56
 
55
- protected_result= rule2.call(protected_file)
56
- result2a = rule2.call(@okay_file)
57
+ protected_result= rule2.violation?(protected_file)
58
+ result2a = rule2.violation?(@okay_file)
57
59
 
58
60
  protected_result.must_equal true
59
61
  result2a .must_equal false
@@ -62,16 +64,16 @@ CODE
62
64
 
63
65
  it "correctly builds rule for eval" do
64
66
  code3 = "eval"
65
- rule3 = LawDSL.parse(code3)
67
+ rule3 = Rule.new(code3)
66
68
 
67
- eval_file = <<CODE
68
- def not_really
69
- eval('1 + 1')
70
- end
71
- CODE
69
+ eval_file = %{
70
+ def not_really
71
+ eval('1 + 1')
72
+ end
73
+ }
72
74
 
73
- eval_result = rule3.call(eval_file)
74
- result3a = rule3.call(@okay_file)
75
+ eval_result = rule3.violation?(eval_file)
76
+ result3a = rule3.violation?(@okay_file)
75
77
 
76
78
  eval_result.must_equal true
77
79
  result3a.must_equal false
@@ -80,15 +82,15 @@ CODE
80
82
 
81
83
  it "correctly builds rule for module" do
82
84
  code4 = "module :name end"
83
- rule4 = LawDSL.parse(code4)
85
+ rule4 = Rule.new(code4)
84
86
 
85
- module_file = <<CODE
86
- module Thing
87
- end
88
- CODE
87
+ module_file = %{
88
+ module Thing
89
+ end
90
+ }
89
91
 
90
- module_result = rule4.call(module_file)
91
- result4a = rule4.call(@okay_file)
92
+ module_result = rule4.violation?(module_file)
93
+ result4a = rule4.violation?(@okay_file)
92
94
 
93
95
  module_result.must_equal true
94
96
  result4a.must_equal false
@@ -96,75 +98,73 @@ CODE
96
98
 
97
99
  it "correctly builds rule for core" do
98
100
  code5 = "class :symbol < :core_class"
99
- rule5 = LawDSL.parse(code5)
100
-
101
- core_file = <<CODE
102
- class Whatever < String
103
- def badthing(here)
104
- @here = here
105
- end
106
- end
107
- CODE
108
- core_result = rule5.call(core_file)
109
- result5a = rule5.call(@okay_file)
101
+ rule5 = Rule.new(code5)
102
+
103
+ core_file = %{
104
+ class Whatever < String
105
+ def badthing(here)
106
+ @here = here
107
+ end
108
+ end
109
+ }
110
+ core_result = rule5.violation?(core_file)
111
+ result5a = rule5.violation?(@okay_file)
110
112
  core_result .must_equal true
111
113
  result5a.must_equal false
112
114
  end
113
115
 
114
-
115
- # it "correctly builds rule for unless else" do
116
- # code6 = "unless :symbols
117
- # :disjoint_code_seperator
118
- # else :more_symbols"
119
- # rule6 = LawDSL.parse(code6)
120
-
121
- # core_file = <<CODE
122
- # class Whatever < String
123
- # def badthing(here)
124
- # @here = here
125
- # end
126
- # end
127
- # CODE
128
-
129
116
  it "correctly builds rule for rescue nil" do
130
117
  code7 = "rescue nil"
131
- rule7 = LawDSL.parse(code7)
132
-
133
- nil_file = <<CODE
134
- begin
135
- "hi"
136
- rescue nil
137
- "bye"
138
- end
139
- CODE
140
- nil_result = rule7.call(nil_file)
141
- result7a = rule7.call(@okay_file)
118
+ rule7 = Rule.new(code7)
119
+
120
+ nil_file = %{
121
+ begin
122
+ "hi"
123
+ rescue nil
124
+ "bye"
125
+ end
126
+ }
127
+ nil_result = rule7.violation?(nil_file)
128
+ result7a = rule7.violation?(@okay_file)
142
129
  nil_result .must_equal true
143
130
  result7a.must_equal false
144
131
  end
145
132
 
146
133
  it "correctly builds rule for inherit struct.new" do
147
134
  code8 = "class :symbol < Struct.new"
148
- rule8 = LawDSL.parse(code8)
135
+ rule8 = Rule.new(code8)
149
136
 
150
- struct_file = <<CODE
151
- class MyClass < Struct.new("Customer", :name, :address)
152
- CODE
137
+ struct_file = %{
138
+ class MyClass < Struct.new("Customer", :name, :address)
139
+ }
153
140
 
154
- struct_result = rule8.call(struct_file)
155
- result8a = rule8.call(@okay_file)
141
+ struct_result = rule8.violation?(struct_file)
142
+ result8a = rule8.violation?(@okay_file)
156
143
 
157
144
  struct_result.must_equal true
158
145
  result8a.must_equal false
159
146
  end
160
147
 
161
-
162
- # end
163
-
164
- it "returns a hash with key counts and nil placeholders" do
165
- params = Rule.send(:params_count_hash, [/module/, :token1, :token2, :token1, /class/, :token3, /end/])
166
- params.keys.size.must_equal 3
167
- params[:token1].last.must_equal 2
148
+ it "correctly builds whitespace sensitive rule" do
149
+ code9 = ":vertical_whitespace_sensitive end\ndef"
150
+ rule9 = Rule.new(code9)
151
+
152
+ def_file = %{
153
+ class Mine
154
+ def method
155
+ true
156
+ end
157
+ def method2
158
+ false
159
+ end
160
+ end
161
+ }
162
+
163
+ def_result = rule9.violation?(def_file)
164
+ result9a = rule9.violation?(@okay_file)
165
+
166
+ def_result.must_equal true
167
+ result9a.must_equal false
168
168
  end
169
169
 
170
170
  it "returns a hash with key counts and nil placeholders" do
@@ -174,7 +174,7 @@ CODE
174
174
  end
175
175
 
176
176
  it "returns a block from build_block method" do
177
- block = LawDSL.send(:build_block,"@@")
177
+ block = LawParser.send(:build_block,"@@")
178
178
  assert_kind_of Proc, block
179
179
  end
180
180
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: outlaw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-25 00:00:00.000000000 Z
12
+ date: 2012-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70266835445120 !ruby/object:Gem::Requirement
16
+ requirement: &20326092 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.9.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70266835445120
24
+ version_requirements: *20326092
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &70266835444560 !ruby/object:Gem::Requirement
27
+ requirement: &20325792 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70266835444560
35
+ version_requirements: *20325792
36
36
  description: ! " Keep bad code out of your projects. Your idea of bad code, no
37
37
  one elses.\n\n Outlaw defines an example based DSL for demonstrating anti-patterns
38
38
  and\n builds a rule for each anti-pattern that it alerts the user to violations\n
@@ -56,8 +56,9 @@ files:
56
56
  - examples/.outlawed.example
57
57
  - lib/outlaw.rb
58
58
  - lib/outlaw/enforcement.rb
59
- - lib/outlaw/law_dsl.rb
59
+ - lib/outlaw/law_parser.rb
60
60
  - lib/outlaw/rule.rb
61
+ - lib/outlaw/rule_methods.rb
61
62
  - lib/outlaw/version.rb
62
63
  - outlaw.gemspec
63
64
  - test/outlaw_test.rb
@@ -1,69 +0,0 @@
1
- module Outlaw
2
- module LawDSL
3
- class << self
4
- def parse(restriction, message="")
5
- tokens = restriction.split
6
- parsed_restriction = []
7
- tokens.each do |token|
8
- case
9
- when special_case?(token)
10
- next #TODO - handle AST branches/disjoint code/meta-symbols to be defined
11
- when multipart?(token) #this handles multi-token literals, Const.new etc
12
- parsed_restriction += Ripper.lex(token)
13
- .reduce([]){|array, tkn|
14
- array << token_type_regex(tkn) }
15
- when defined_collection?(token)
16
- parsed_restriction << Outlaw.const_get(string_to_sym(token.upcase))
17
- when parameter?(token)
18
- parsed_restriction << string_to_sym(token)
19
- else
20
- parsed_restriction += build_regex(token)
21
- end
22
- end
23
- Rule.new(message, restriction, &build_block(parsed_restriction))
24
- end
25
-
26
- private
27
-
28
- def token_type_regex(token)
29
- /#{token[2]}/
30
- end
31
-
32
- def parameter?(token)
33
- token[0].chr == ':'
34
- end
35
-
36
- def special_case?(token)
37
- SPECIAL_CASES.include? token
38
- end
39
-
40
- def defined_collection?(token)
41
- parameter?(token) && Outlaw.const_defined?(string_to_sym(token.upcase))
42
- end
43
-
44
- def string_to_sym(str)
45
- str[1..-1].to_sym
46
- end
47
-
48
- def build_regex(token)
49
- #fully expect this hack to come back & haunt me, but passes curr. examples
50
- [/\A#{token}/]
51
- end
52
-
53
- def multipart?(token)
54
- !parameter?(token) && Ripper.lex(token).count > 1
55
- end
56
-
57
- def build_block(pattern)
58
- lambda do |file|
59
- program = Ripper.tokenize(file)
60
- program.each_with_index do |token, index|
61
- next unless token.match(pattern.first)
62
- return true if Rule.test(program, index, pattern)
63
- end
64
- return false
65
- end
66
- end
67
- end
68
- end
69
- end