joker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.markdown +6 -0
- data/LICENSE.txt +23 -0
- data/README.markdown +70 -0
- data/Rakefile +20 -0
- data/VERSION +1 -0
- data/lib/joker.rb +179 -0
- data/test/test_joker.rb +59 -0
- metadata +62 -0
data/HISTORY.markdown
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2009 Fabian Streitel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/README.markdown
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Joker #
|
2
|
+
|
3
|
+
<http://karottenreibe.github.com/joker>
|
4
|
+
|
5
|
+
Joker is a simple Wildcard (a.k.a Glob Pattern) implementition
|
6
|
+
for Ruby.
|
7
|
+
|
8
|
+
## Features ##
|
9
|
+
|
10
|
+
* Behaves much like Regexp
|
11
|
+
* ` * ` and ` ? ` as wildcard characters
|
12
|
+
* ` \ ` for escaping
|
13
|
+
* `\a` matches `\a`, but not `a`
|
14
|
+
* Wildcards must always match whole string
|
15
|
+
* Wildcards can be case insensitive
|
16
|
+
|
17
|
+
## Installation ##
|
18
|
+
|
19
|
+
gem install karottenreibe-joker --source http://gems.github.com
|
20
|
+
gem install joker
|
21
|
+
|
22
|
+
## Usage ##
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'joker'
|
26
|
+
|
27
|
+
|
28
|
+
wild = Wildcard['Fairy?ake*']
|
29
|
+
|
30
|
+
wild =~ 'Fairycake' #=> true
|
31
|
+
wild =~ 'Fairyfakes' #=> true
|
32
|
+
wild =~ 'Fairylake is a cool place' #=> true
|
33
|
+
|
34
|
+
wild =~ 'Dairycake' #=> false
|
35
|
+
wild =~ 'Fairysteakes' #=> false
|
36
|
+
wild =~ 'fairycake' #=> false
|
37
|
+
|
38
|
+
wildi = Wildcard['Fairy?ake*\?', true]
|
39
|
+
|
40
|
+
wildi =~ 'FairyCake?' #=> true
|
41
|
+
wildi =~ 'fairyfakes?' #=> true
|
42
|
+
wildi =~ 'FairyLake IS A COOL Place?' #=> true
|
43
|
+
|
44
|
+
Wildcard.quote('*?\\') #=> '\\*\\?\\\\'
|
45
|
+
|
46
|
+
## License ##
|
47
|
+
|
48
|
+
Copyright (c) 2009 Fabian Streitel
|
49
|
+
|
50
|
+
Permission is hereby granted, free of charge, to any person
|
51
|
+
obtaining a copy of this software and associated documentation
|
52
|
+
files (the "Software"), to deal in the Software without
|
53
|
+
restriction, including without limitation the rights to use,
|
54
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
55
|
+
copies of the Software, and to permit persons to whom the
|
56
|
+
Software is furnished to do so, subject to the following
|
57
|
+
conditions:
|
58
|
+
|
59
|
+
The above copyright notice and this permission notice shall be
|
60
|
+
included in all copies or substantial portions of the Software.
|
61
|
+
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
63
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
64
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
65
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
66
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
67
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
68
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
69
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
70
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'jeweler'
|
2
|
+
|
3
|
+
task :build => :gemspec
|
4
|
+
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.name = 'joker'
|
7
|
+
gem.summary = gem.description =
|
8
|
+
'Joker is a simple wildcard implementation that works much like Regexps'
|
9
|
+
gem.email = 'karottenreibe@gmail.com'
|
10
|
+
gem.homepage = 'http://karottenreibe.github.com/joker'
|
11
|
+
gem.authors = ['Fabian Streitel']
|
12
|
+
gem.rubyforge_project = 'k-gems'
|
13
|
+
end
|
14
|
+
|
15
|
+
Jeweler::RubyforgeTasks.new
|
16
|
+
|
17
|
+
task :test do
|
18
|
+
sh 'bacon -Ilib test/test_*.rb'
|
19
|
+
end
|
20
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/joker.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# Joker is a simple Wildcard implementation that works much like Regexps.
|
3
|
+
#
|
4
|
+
|
5
|
+
#
|
6
|
+
# Implements wildcards for Ruby. Modeled after the Regexp class.
|
7
|
+
#
|
8
|
+
# This implementation supports the following special characters:
|
9
|
+
#
|
10
|
+
# - ? matches a single character
|
11
|
+
# - * matches any number of characters, including 0
|
12
|
+
# - \\* matches a literal '*'
|
13
|
+
# - \\? matches a literal '?'
|
14
|
+
# - \\\\ matches a literal '\\'
|
15
|
+
# - [xyz] matches either 'x', 'y' or 'z'. NOTE that you have
|
16
|
+
# to escape ']' in these groups: \\]
|
17
|
+
#
|
18
|
+
# NOTE that '\\a' will match the literal string '\\a', not 'a' as
|
19
|
+
# one might expect.
|
20
|
+
#
|
21
|
+
# wild = Wildcard['Fairy?ake*']
|
22
|
+
# wild =~ 'Fairycake' #=> true
|
23
|
+
# wild =~ 'Fairyfakes are mean' #=> true
|
24
|
+
# wild =~ 'Fairysteakes are delicious' #=> false
|
25
|
+
#
|
26
|
+
# Also there is a case sensitivity flag. By default it is set to true,
|
27
|
+
# but it can be turned off at construction time:
|
28
|
+
#
|
29
|
+
# wild = Wildcard['Fairy?ake*', true]
|
30
|
+
# wild =~ 'Fairycake'
|
31
|
+
# wild =~ 'fairyCAKE'
|
32
|
+
# wild =~ 'FaIrYfAkEs, the Movie'
|
33
|
+
#
|
34
|
+
# Furthermore, any given Wildcard expression must match the whole string:
|
35
|
+
#
|
36
|
+
# wild = Wildcard['Fairy?ake']
|
37
|
+
# wild =~ 'some Fairycake' #=> false
|
38
|
+
# wild =~ 'Fairycake is good for you' #=> false
|
39
|
+
#
|
40
|
+
class Wildcard
|
41
|
+
|
42
|
+
#
|
43
|
+
# Boolean. Determines case sensitivity of the Wildcard.
|
44
|
+
#
|
45
|
+
# If this is true, the Wildcard will ignore case.
|
46
|
+
#
|
47
|
+
attr_reader :casefold
|
48
|
+
|
49
|
+
#
|
50
|
+
# The string from which the Wildcard was constructed.
|
51
|
+
#
|
52
|
+
attr_reader :source
|
53
|
+
|
54
|
+
#
|
55
|
+
# Creates a new Wildcard from the given string.
|
56
|
+
# If casefold is true, the Wildcard will ignore case.
|
57
|
+
#
|
58
|
+
def initialize( wildcard_string, casefold = false )
|
59
|
+
@source = wildcard_string
|
60
|
+
@casefold = casefold
|
61
|
+
@regexp =
|
62
|
+
if casefold then Regexp.new(compile, Regexp::IGNORECASE)
|
63
|
+
else Regexp.new(compile)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
|
69
|
+
#
|
70
|
+
# Returns a new string with any characters escaped that would have
|
71
|
+
# special meaning in a Wildcard.
|
72
|
+
#
|
73
|
+
def quote( string )
|
74
|
+
string.gsub(%r{[\\?*\[]}) { |char| "\\#{char}" }
|
75
|
+
end
|
76
|
+
|
77
|
+
alias_method :[], :new
|
78
|
+
alias_method :compile, :new
|
79
|
+
alias_method :escape, :quote
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def inspect
|
84
|
+
%{Wildcard[#{@source.inspect}]#{@casefold ? 'i' : ''}}
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Matches the wildcard against $_:
|
89
|
+
#
|
90
|
+
# $_ = 'I love fairycakes'
|
91
|
+
# ~Wildcard['*fairy*'] #=> true
|
92
|
+
#
|
93
|
+
def ~
|
94
|
+
self =~ $_
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Matches the Wildcard against the given string.
|
99
|
+
#
|
100
|
+
# NOTE: Since a wildcard has to match the whole string,
|
101
|
+
# this method only returns true or false, not the position
|
102
|
+
# of the match.
|
103
|
+
#
|
104
|
+
# Wildcard['*fairy*'] =~ 'I love fairycake' #=> true
|
105
|
+
# 'I love fairycake' =~ Wildcard['*dairy*'] #=> false
|
106
|
+
#
|
107
|
+
def =~( string )
|
108
|
+
!!(@regexp =~ string)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# The case operator. Allows you to use Wildcards in case
|
113
|
+
# expressions:
|
114
|
+
#
|
115
|
+
# case 'I love fairycake'
|
116
|
+
# when Wildcard['*fairy*'] then puts 'fairy!'
|
117
|
+
# else puts 'no fairy...'
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
def ===( object )
|
121
|
+
!!(@regexp =~ object)
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Compares to Wildcards for equality.
|
126
|
+
#
|
127
|
+
# Two wildcards are equal, if they were constructed from the
|
128
|
+
# same string and have the same #casefold?().
|
129
|
+
#
|
130
|
+
def eql?( that )
|
131
|
+
return false unless that.is_a?(Wildcard)
|
132
|
+
@source == that.source && @casefold == that.casefold
|
133
|
+
end
|
134
|
+
|
135
|
+
alias_method :==, :eql?
|
136
|
+
alias_method :casefold?, :casefold
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
#
|
141
|
+
# Converts the wildcard string into a Regexp.
|
142
|
+
# A simple parser, I just threw it in there, no
|
143
|
+
# optimizations.
|
144
|
+
#
|
145
|
+
def compile
|
146
|
+
ptr = 0
|
147
|
+
compiled = '^'
|
148
|
+
while ptr < @source.length
|
149
|
+
snip = @source[ptr..-1]
|
150
|
+
if snip.scan(%r{^\\\\}).first
|
151
|
+
compiled << '\\\\'
|
152
|
+
ptr += 2
|
153
|
+
elsif snip.scan(%r{^\\\?}).first
|
154
|
+
compiled << '\\?'
|
155
|
+
ptr += 2
|
156
|
+
elsif snip.scan(%r{^\\\*}).first
|
157
|
+
compiled << '\\*'
|
158
|
+
ptr += 2
|
159
|
+
elsif snip.scan(%r{^\?}).first
|
160
|
+
compiled << '.'
|
161
|
+
ptr += 1
|
162
|
+
elsif snip.scan(%r{^\*}).first
|
163
|
+
compiled << '.*'
|
164
|
+
ptr += 1
|
165
|
+
elsif group = snip.scan(%r{^\[(?:\\\]|[^\]])+\]}).first
|
166
|
+
ptr += group.length
|
167
|
+
group = group[1..-2] # remove []
|
168
|
+
group = group.gsub(%r{\\\]}) { ']' }
|
169
|
+
compiled << '[' << Regexp.quote(group) << ']'
|
170
|
+
else
|
171
|
+
compiled << Regexp.quote(@source[ptr..ptr])
|
172
|
+
ptr += 1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
compiled + '$'
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
data/test/test_joker.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'bacon'
|
2
|
+
require 'joker'
|
3
|
+
|
4
|
+
describe 'A Wildcard' do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@wild ||= Wildcard['Fairy?ake*']
|
8
|
+
@wildi ||= Wildcard['Fairy?ake*\?', true]
|
9
|
+
@wildc ||= Wildcard['Fairy[cf]ake[!\\]]']
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should be constructed correctly' do
|
13
|
+
@wild.casefold?.should.be.false
|
14
|
+
@wildi.casefold?.should.be.true
|
15
|
+
@wildc.casefold?.should.be.false
|
16
|
+
regexp = @wild.instance_variable_get(:@regexp)
|
17
|
+
regexpi = @wildi.instance_variable_get(:@regexp)
|
18
|
+
regexpc = @wildc.instance_variable_get(:@regexp)
|
19
|
+
regexp.should.be == /^Fairy.ake.*$/
|
20
|
+
regexpi.should.be == /^Fairy.ake.*\?$/i
|
21
|
+
regexpc.should.be == /^Fairy[cf]ake[!\]]$/
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should match correct strings' do
|
25
|
+
@wild.should =~ 'Fairycake'
|
26
|
+
@wild.should =~ 'Fairyfakes'
|
27
|
+
@wild.should =~ 'Fairylake is a cool place'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not match incorrcet strings' do
|
31
|
+
@wild.should.not =~ 'Dairycake'
|
32
|
+
@wild.should.not =~ 'Fairysteakes'
|
33
|
+
@wild.should.not =~ 'fairycake'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should match case insensitive' do
|
37
|
+
@wildi.should =~ 'FairyCake?'
|
38
|
+
@wildi.should =~ 'fairyfakes?'
|
39
|
+
@wildi.should =~ 'FairyLake IS A COOL Place?'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should handle escapes correctly' do
|
43
|
+
wild = Wildcard['\\\\a\\?b\\*c\\d.][+'] # \\a\?b\*c\d.][+
|
44
|
+
regexp = wild.instance_variable_get(:@regexp)
|
45
|
+
regexp.should.be == /^\\a\?b\*c\\d\.\]\[\+$/
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should quote correctly' do
|
49
|
+
Wildcard.quote('*?\\').should.be == '\\*\\?\\\\' # *?\ --> \*\?\\
|
50
|
+
Wildcard.quote('\\\\').should.be == '\\\\\\\\' # \\ --> \\\\
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should know about character classes' do
|
54
|
+
@wildc.should =~ 'Fairycake!'
|
55
|
+
@wildc.should =~ 'Fairyfake]'
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fabian Streitel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-15 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Joker is a simple wildcard implementation that works much like Regexps
|
17
|
+
email: karottenreibe@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.markdown
|
25
|
+
files:
|
26
|
+
- HISTORY.markdown
|
27
|
+
- LICENSE.txt
|
28
|
+
- README.markdown
|
29
|
+
- Rakefile
|
30
|
+
- VERSION
|
31
|
+
- lib/joker.rb
|
32
|
+
- test/test_joker.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://karottenreibe.github.com/joker
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project: k-gems
|
57
|
+
rubygems_version: 1.3.5
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Joker is a simple wildcard implementation that works much like Regexps
|
61
|
+
test_files:
|
62
|
+
- test/test_joker.rb
|