machete 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ lib/machete/parser.rb
2
2
  doc/
3
3
  .yardoc
4
4
  *.rbc
5
+ Gemfile.lock
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 0.4.0 (2011-10-18)
2
+ ------------------
3
+ * Support for "true", "false" and "nil" literals.
4
+ * New "*=" operator matching part of a string.
5
+ * Bundler support.
6
+
1
7
  0.3.0 (2011-09-27)
2
8
  ------------------
3
9
 
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md CHANGED
@@ -70,18 +70,20 @@ If you want to match a specific attribute of a node, specify its value inside `<
70
70
  Machete.matches?('42'.to_ast, 'FixnumLiteral<value = 42>') # => true
71
71
  Machete.matches?('45'.to_ast, 'FixnumLiteral<value = 42>') # => false
72
72
 
73
- The attribute value can be an integer, string, symbol, array or other pattern. The last option means you can easily match nested nodes recursively. You can also specify multiple attributes:
73
+ The attribute value can be `true`, `false`, `nil`, integer, string, symbol, array or other pattern. The last option means you can easily match nested nodes recursively. You can also specify multiple attributes:
74
74
 
75
75
  Machete.matches?('foo.bar'.to_ast, 'Send<receiver = Send<receiver = Self, name = :foo>, name = :bar>') # => true
76
76
 
77
77
  #### String Attributes
78
78
 
79
- When matching string attributes values, you don't have to do a whole-string match using the `=` operator. You can also match the beginning or the end of a string attribute value using the `^=` or `$=` operators:
79
+ When matching string attributes values, you don't have to do a whole-string match using the `=` operator. You can also match the beginning, the end or a part of a string attribute value using the `^=`, `$=` and `*=` operators:
80
80
 
81
81
  Machete.matches?('"abcd"'.to_ast, 'StringLiteral<string ^= "ab">') # => true
82
82
  Machete.matches?('"efgh"'.to_ast, 'StringLiteral<string ^= "ab">') # => false
83
83
  Machete.matches?('"abcd"'.to_ast, 'StringLiteral<string $= "cd">') # => true
84
84
  Machete.matches?('"efgh"'.to_ast, 'StringLiteral<string $= "cd">') # => false
85
+ Machete.matches?('"abcd"'.to_ast, 'StringLiteral<string *= "bc">') # => true
86
+ Machete.matches?('"efgh"'.to_ast, 'StringLiteral<string *= "bc">') # => false
85
87
 
86
88
  #### Array Attributes
87
89
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -137,36 +137,19 @@ module Machete
137
137
  end
138
138
 
139
139
  # @private
140
- class StartsWithMatcher
141
- attr_reader :prefix
140
+ class StringRegexpMatcher
141
+ attr_reader :regexp
142
142
 
143
- def initialize(prefix)
144
- @prefix = prefix
143
+ def initialize(regexp)
144
+ @regexp = regexp
145
145
  end
146
146
 
147
147
  def ==(other)
148
- other.instance_of?(self.class) && @prefix == other.prefix
148
+ other.instance_of?(self.class) && @regexp == other.regexp
149
149
  end
150
150
 
151
151
  def matches?(node)
152
- node.is_a?(String) && node.start_with?(@prefix)
153
- end
154
- end
155
-
156
- # @private
157
- class EndsWithMatcher
158
- attr_reader :suffix
159
-
160
- def initialize(suffix)
161
- @suffix = suffix
162
- end
163
-
164
- def ==(other)
165
- other.instance_of?(self.class) && @suffix == other.suffix
166
- end
167
-
168
- def matches?(node)
169
- node.is_a?(String) && node.end_with?(@suffix)
152
+ node.is_a?(String) && node =~ @regexp
170
153
  end
171
154
  end
172
155
 
@@ -1,5 +1,8 @@
1
1
  class Machete::Parser
2
2
 
3
+ token TRUE
4
+ token FALSE
5
+ token NIL
3
6
  token INTEGER
4
7
  token STRING
5
8
  token ANY
@@ -40,12 +43,23 @@ attrs : attr
40
43
  attr : method_name "=" expression { result = { val[0].to_sym => val[2] } }
41
44
  | method_name "^=" STRING {
42
45
  result = {
43
- val[0].to_sym => StartsWithMatcher.new(string_value(val[2]))
46
+ val[0].to_sym => StringRegexpMatcher.new(
47
+ Regexp.new("^" + Regexp.escape(string_value(val[2])))
48
+ )
44
49
  }
45
50
  }
46
51
  | method_name "$=" STRING {
47
52
  result = {
48
- val[0].to_sym => EndsWithMatcher.new(string_value(val[2]))
53
+ val[0].to_sym => StringRegexpMatcher.new(
54
+ Regexp.new(Regexp.escape(string_value(val[2])) + "$")
55
+ )
56
+ }
57
+ }
58
+ | method_name "*=" STRING {
59
+ result = {
60
+ val[0].to_sym => StringRegexpMatcher.new(
61
+ Regexp.new(Regexp.escape(string_value(val[2])))
62
+ )
49
63
  }
50
64
  }
51
65
 
@@ -53,6 +67,9 @@ attr : method_name "=" expression { result = { val[0].to_sym => val[2] } }
53
67
  # METHOD_NAME tokens, and that "reserved words" will lex as separate kinds of
54
68
  # tokens.
55
69
  method_name : METHOD_NAME
70
+ | TRUE
71
+ | FALSE
72
+ | NIL
56
73
  | ANY
57
74
  | EVEN
58
75
  | ODD
@@ -95,6 +112,9 @@ quantifier : "*" { result = [0, nil, 1] }
95
112
  literal : SYMBOL { result = LiteralMatcher.new(val[0][1..-1].to_sym) }
96
113
  | INTEGER { result = LiteralMatcher.new(integer_value(val[0])) }
97
114
  | STRING { result = LiteralMatcher.new(string_value(val[0])) }
115
+ | TRUE { result = LiteralMatcher.new(true) }
116
+ | FALSE { result = LiteralMatcher.new(false) }
117
+ | NIL { result = LiteralMatcher.new(nil) }
98
118
 
99
119
  any : ANY { result = AnyMatcher.new }
100
120
 
@@ -166,6 +186,7 @@ SIMPLE_TOKENS = [
166
186
  "$=",
167
187
  "[",
168
188
  "]",
189
+ "*=",
169
190
  "*",
170
191
  "+",
171
192
  "?",
@@ -174,6 +195,9 @@ SIMPLE_TOKENS = [
174
195
  ]
175
196
 
176
197
  COMPLEX_TOKENS = [
198
+ [:TRUE, /^true/],
199
+ [:FALSE, /^false/],
200
+ [:NIL, /^nil/],
177
201
  # INTEGER needs to be before METHOD_NAME, otherwise e.g. "+1" would be
178
202
  # recognized as two tokens.
179
203
  [
@@ -409,14 +409,14 @@ module Machete::Matchers
409
409
  end
410
410
  end
411
411
 
412
- describe StartsWithMatcher do
412
+ describe StringRegexpMatcher do
413
413
  before :each do
414
- @matcher = StartsWithMatcher.new("abcd")
414
+ @matcher = StringRegexpMatcher.new(/abcd/)
415
415
  end
416
416
 
417
417
  describe "initialize" do
418
418
  it "sets attributes correctly" do
419
- @matcher.prefix.should == "abcd"
419
+ @matcher.regexp.should == /abcd/
420
420
  end
421
421
  end
422
422
 
@@ -426,7 +426,7 @@ module Machete::Matchers
426
426
  end
427
427
 
428
428
  it "returns true when passed a StartsWithMatcher initialized with the same parameters" do
429
- @matcher.should == StartsWithMatcher.new("abcd")
429
+ @matcher.should == StringRegexpMatcher.new(/abcd/)
430
430
  end
431
431
 
432
432
  it "returns false when passed some random object" do
@@ -434,23 +434,23 @@ module Machete::Matchers
434
434
  end
435
435
 
436
436
  it "returns false when passed a subclass of StartsWithMatcher initialized with the same parameters" do
437
- class SubclassedStartsWithMatcher < StartsWithMatcher
437
+ class SubclassedStringRegexpMatcher < StringRegexpMatcher
438
438
  end
439
439
 
440
- @matcher.should_not == SubclassedStartsWithMatcher.new("abcd")
440
+ @matcher.should_not == SubclassedStringRegexpMatcher.new(/abcd/)
441
441
  end
442
442
 
443
443
  it "returns false when passed a StartsWithMatcher initialized with different parameters" do
444
- @matcher.should_not == StartsWithMatcher.new("efgh")
444
+ @matcher.should_not == StringRegexpMatcher.new(/efgh/)
445
445
  end
446
446
  end
447
447
 
448
448
  describe "matches?" do
449
- it "matches a string starting with the prefix" do
450
- @matcher.matches?("abcdefgh").should be_true
449
+ it "matches a string matching the regexp" do
450
+ @matcher.matches?("efghabcdijkl").should be_true
451
451
  end
452
452
 
453
- it "does not match a string not starting with the prefix" do
453
+ it "does not match a string not matching the regexp" do
454
454
  @matcher.matches?("efghijkl").should be_false
455
455
  end
456
456
 
@@ -460,57 +460,6 @@ module Machete::Matchers
460
460
  end
461
461
  end
462
462
 
463
- describe EndsWithMatcher do
464
- before :each do
465
- @matcher = EndsWithMatcher.new("abcd")
466
- end
467
-
468
- describe "initialize" do
469
- it "sets attributes correctly" do
470
- @matcher.suffix.should == "abcd"
471
- end
472
- end
473
-
474
- describe "==" do
475
- it "returns true when passed the same object" do
476
- @matcher.should == @matcher
477
- end
478
-
479
- it "returns true when passed a EndsWithMatcher initialized with the same parameters" do
480
- @matcher.should == EndsWithMatcher.new("abcd")
481
- end
482
-
483
- it "returns false when passed some random object" do
484
- @matcher.should_not == Object.new
485
- end
486
-
487
- it "returns false when passed a subclass of EndsWithMatcher initialized with the same parameters" do
488
- class SubclassedEndsWithMatcher < EndsWithMatcher
489
- end
490
-
491
- @matcher.should_not == SubclassedEndsWithMatcher.new("abcd")
492
- end
493
-
494
- it "returns false when passed a EndsWithMatcher initialized with different parameters" do
495
- @matcher.should_not == EndsWithMatcher.new("efgh")
496
- end
497
- end
498
-
499
- describe "matches?" do
500
- it "matches a string ending with the suffix" do
501
- @matcher.matches?("efghabcd").should be_true
502
- end
503
-
504
- it "does not match a string not ending with the suffix" do
505
- @matcher.matches?("ijklefgh").should be_false
506
- end
507
-
508
- it "does not match some random object" do
509
- @matcher.matches?(Object.new).should be_false
510
- end
511
- end
512
- end
513
-
514
463
  describe AnyMatcher do
515
464
  before :each do
516
465
  @matcher = AnyMatcher.new
@@ -74,16 +74,37 @@ module Machete
74
74
  it "parses attr" do
75
75
  'Foo<a = 42 | 43>'.should be_parsed_as(NodeMatcher.new(:Foo, :a => @ch4243))
76
76
  'Foo<a ^= "abcd">'.should be_parsed_as(
77
- NodeMatcher.new(:Foo, :a => StartsWithMatcher.new("abcd"))
77
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(/^abcd/))
78
+ )
79
+ 'Foo<a ^= "[]{}()|-*.\\?+^$ #\t\f\v\n\r">'.should be_parsed_as(
80
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(
81
+ /^\[\]\{\}\(\)\|\-\*\.\\\?\+\^\$\ \#\t\f\v\n\r/
82
+ ))
78
83
  )
79
84
  'Foo<a $= "abcd">'.should be_parsed_as(
80
- NodeMatcher.new(:Foo, :a => EndsWithMatcher.new("abcd"))
85
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(/abcd$/))
86
+ )
87
+ 'Foo<a $= "[]{}()|-*.\\?+^$ #\t\f\v\n\r">'.should be_parsed_as(
88
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(
89
+ /\[\]\{\}\(\)\|\-\*\.\\\?\+\^\$\ \#\t\f\v\n\r$/
90
+ ))
91
+ )
92
+ 'Foo<a *= "abcd">'.should be_parsed_as(
93
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(/abcd/))
94
+ )
95
+ 'Foo<a *= "[]{}()|-*.\\?+^$ #\t\f\v\n\r">'.should be_parsed_as(
96
+ NodeMatcher.new(:Foo, :a => StringRegexpMatcher.new(
97
+ /\[\]\{\}\(\)\|\-\*\.\\\?\+\^\$\ \#\t\f\v\n\r/
98
+ ))
81
99
  )
82
100
  end
83
101
 
84
102
  # Canonical method_name is "a".
85
103
  it "parses method_name" do
86
104
  'Foo<a = 42>'.should be_parsed_as(node_matcher_with_attr(:a))
105
+ 'Foo<true = 42>'.should be_parsed_as(node_matcher_with_attr(:true))
106
+ 'Foo<false = 42>'.should be_parsed_as(node_matcher_with_attr(:false))
107
+ 'Foo<any = 42>'.should be_parsed_as(node_matcher_with_attr(:any))
87
108
  'Foo<any = 42>'.should be_parsed_as(node_matcher_with_attr(:any))
88
109
  'Foo<even = 42>'.should be_parsed_as(node_matcher_with_attr(:even))
89
110
  'Foo<odd = 42>'.should be_parsed_as(node_matcher_with_attr(:odd))
@@ -148,6 +169,9 @@ module Machete
148
169
  ':a'.should be_parsed_as(LiteralMatcher.new(:a))
149
170
  '42'.should be_parsed_as(@i42)
150
171
  '"abcd"'.should be_parsed_as(LiteralMatcher.new("abcd"))
172
+ 'true'.should be_parsed_as(LiteralMatcher.new(true))
173
+ 'false'.should be_parsed_as(LiteralMatcher.new(false))
174
+ 'nil'.should be_parsed_as(LiteralMatcher.new(nil))
151
175
  end
152
176
 
153
177
  # Canonical any is "any".
@@ -155,6 +179,21 @@ module Machete
155
179
  'any'.should be_parsed_as(AnyMatcher.new)
156
180
  end
157
181
 
182
+ # Canonical TRUE is "true".
183
+ it "parses TRUE" do
184
+ 'true'.should be_parsed_as(LiteralMatcher.new(true))
185
+ end
186
+
187
+ # Canonical FALSE is "false".
188
+ it "parses FALSE" do
189
+ 'false'.should be_parsed_as(LiteralMatcher.new(false))
190
+ end
191
+
192
+ # Canonical NIL is "nil".
193
+ it "parses NIL" do
194
+ 'nil'.should be_parsed_as(LiteralMatcher.new(nil))
195
+ end
196
+
158
197
  # Canonical INTEGER is "42".
159
198
  it "parses INTEGER" do
160
199
  # Sign
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: machete
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - David Majda
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-27 00:00:00 +02:00
18
+ date: 2011-10-18 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -100,6 +100,7 @@ files:
100
100
  - .gitignore
101
101
  - .yardopts
102
102
  - CHANGELOG
103
+ - Gemfile
103
104
  - LICENSE
104
105
  - README.md
105
106
  - Rakefile