joker 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ #ifndef MATCH_H_GUARD
2
+ #define MATCH_H_GUARD
3
+
4
+ #include "Wildcard.h"
5
+ #include "stdbool.h"
6
+
7
+
8
+ /*
9
+ * Matches a given Wildcard against a given string and returns
10
+ * true on success and false otherwise.
11
+ *
12
+ */
13
+ bool Wildcard_match(
14
+ Wildcard * wildcard, // The wildcard to match
15
+ const char * cstring, // The string to match against
16
+ const long int len, // The length of the string
17
+ bool casefold); // Whether to ignore character case
18
+
19
+
20
+ #endif
21
+
@@ -2,6 +2,8 @@
2
2
  # Joker is a simple Wildcard implementation that works much like Regexps.
3
3
  #
4
4
 
5
+ require File.join( File.dirname( File.expand_path(__FILE__)), 'joker_native')
6
+
5
7
  #
6
8
  # Implements wildcards for Ruby. Modeled after the Regexp class.
7
9
  #
@@ -54,6 +56,7 @@ class Wildcard
54
56
  #
55
57
  # Creates a new Wildcard from the given string.
56
58
  # If casefold is true, the Wildcard will ignore case.
59
+ # TODO
57
60
  #
58
61
  def initialize( wildcard_string, casefold = false )
59
62
  @source = wildcard_string
@@ -71,7 +74,7 @@ class Wildcard
71
74
  # special meaning in a Wildcard.
72
75
  #
73
76
  def quote( string )
74
- string.gsub(%r{[\\?*\[]}) { |char| "\\#{char}" }
77
+ string.gsub(%r{[\\?*\[\]]}) { |char| "\\#{char}" }
75
78
  end
76
79
 
77
80
  alias_method :[], :new
@@ -81,7 +84,7 @@ class Wildcard
81
84
  end
82
85
 
83
86
  def inspect
84
- %{Wildcard[#{@source.inspect}]#{@casefold ? 'i' : ''}}
87
+ %{Wildcard[#{self.source.inspect}]#{self.casefold ? 'i' : ''}}
85
88
  end
86
89
 
87
90
  #
@@ -94,33 +97,6 @@ class Wildcard
94
97
  self =~ $_
95
98
  end
96
99
 
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
100
  #
125
101
  # Compares to Wildcards for equality.
126
102
  #
@@ -129,51 +105,11 @@ class Wildcard
129
105
  #
130
106
  def eql?( that )
131
107
  return false unless that.is_a?(Wildcard)
132
- @source == that.source && @casefold == that.casefold
108
+ self.source == that.source && self.casefold == that.casefold
133
109
  end
134
110
 
135
111
  alias_method :==, :eql?
136
112
  alias_method :casefold?, :casefold
137
113
 
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
114
  end
179
115
 
@@ -0,0 +1,29 @@
1
+ require 'rake/extensiontask'
2
+ require 'rake/extensiontesttask'
3
+
4
+ extension_task =
5
+ Rake::ExtensionTask.new('joker_native', $gemspec) do |ext|
6
+ ext.cross_compile = true
7
+ ext.cross_platform = 'x86-mswin32'
8
+ ext.test_files = FileList['test/c/*']
9
+ end
10
+
11
+ CLEAN.include 'lib/**/*.so'
12
+
13
+
14
+ # workaround for rake-compiler which needs the gemspec to have a
15
+ # version and yaml-dump-loads the
16
+ # gemspec which leads to errors since procs can't be loaded
17
+ Rake::Task.tasks.each do |task_name|
18
+ case task_name.to_s
19
+ when /^native/
20
+ task_name.prerequisites.unshift("gemspec", "fix_rake_compiler_gemspec_dump")
21
+ end
22
+ end
23
+
24
+ task :fix_rake_compiler_gemspec_dump do
25
+ %w{files extra_rdoc_files test_files}.each do |accessor|
26
+ $gemspec.send(accessor).instance_eval { @exclude_procs = Array.new }
27
+ end
28
+ end
29
+
@@ -0,0 +1,28 @@
1
+
2
+ task :release do
3
+ sh "vim HISTORY.markdown"
4
+ sh "vim README.markdown"
5
+ sh "git commit -a -m 'prerelease adjustments'; true"
6
+ end
7
+
8
+ task :build => :gemspec
9
+
10
+ require 'jeweler'
11
+ jeweler_tasks = Jeweler::Tasks.new do |gem|
12
+ gem.name = 'joker'
13
+ gem.summary = 'Joker is a simple wildcard implementation that works much like Regexps'
14
+ gem.description = gem.summary
15
+ gem.email = 'karottenreibe@gmail.com'
16
+ gem.homepage = 'http://karottenreibe.github.com/joker'
17
+ gem.authors = ['Fabian Streitel']
18
+ gem.rubyforge_project = 'k-gems'
19
+ gem.extensions = FileList['ext/**/extconf.rb']
20
+
21
+ gem.files.include('lib/joker_native.*') # add native stuff
22
+ end
23
+
24
+ $gemspec = jeweler_tasks.gemspec
25
+
26
+ Jeweler::RubyforgeTasks.new
27
+ Jeweler::GemcutterTasks.new
28
+
@@ -0,0 +1,9 @@
1
+ require 'rake/rdoctask'
2
+
3
+ Rake::RDocTask.new do |rdoc|
4
+ rdoc.rdoc_dir = 'rdoc'
5
+ rdoc.title = 'Joker'
6
+ rdoc.rdoc_files.include('lib/**/*.rb')
7
+ rdoc.rdoc_files.include('ext/**/*.rb')
8
+ end
9
+
@@ -0,0 +1,22 @@
1
+
2
+ desc("Build linux and windows specific gems")
3
+ task :gems do
4
+ sh "rake clean build:native"
5
+ sh "rake clean build:cross"
6
+ sh "rake clean build"
7
+ end
8
+
9
+ task "build:native" => [:no_extconf, :native, :build] do
10
+ file = "pkg/joker-#{`cat VERSION`.chomp}.gem"
11
+ mv file, "#{file.ext}-i686-linux.gem"
12
+ end
13
+
14
+ task "build:cross" => [:no_extconf, :cross, :native, :build] do
15
+ file = "pkg/joker-#{`cat VERSION`.chomp}.gem"
16
+ mv file, "#{file.ext}-x86-mingw32.gem"
17
+ end
18
+
19
+ task :no_extconf do
20
+ $gemspec.extensions = []
21
+ end
22
+
@@ -0,0 +1,6 @@
1
+
2
+ desc('Test the ruby part of Joker')
3
+ task :test => 'build:native' do
4
+ sh 'bacon -Ilib test/ruby/test_*.rb'
5
+ end
6
+
@@ -0,0 +1,215 @@
1
+ #include <stdarg.h>
2
+ #include <stddef.h>
3
+ #include <stdbool.h>
4
+ #include <setjmp.h>
5
+ #include <cmockery.h>
6
+ #include <stdio.h>
7
+ #include <string.h>
8
+ #include <ruby.h>
9
+ #include "compile.h"
10
+ #include "Wildcard.h"
11
+
12
+ //
13
+ // Possible scenarios:
14
+ // * string empty
15
+ // string not empty
16
+ // * contains group
17
+ // contains fixed
18
+ // contains wildcard
19
+ // contains kleene
20
+ // * contains "**"
21
+ // * contains escape at EOS
22
+ // contains escape at Fixed
23
+ // contains escape at Group
24
+ //
25
+
26
+
27
+ static void generic_test(cstring, length, expected) // {{{1
28
+ const char * cstring;
29
+ const int length;
30
+ const char * expected;
31
+ {
32
+ Wildcard * wildcard;
33
+ int i;
34
+
35
+ wildcard = Wildcard_compile(cstring, strlen(cstring));
36
+ assert_int_not_equal( (int)NULL, (int)wildcard );
37
+ assert_int_not_equal( (int)NULL, (int)wildcard->first );
38
+ assert_int_not_equal( (int)NULL, (int)wildcard->last );
39
+ assert_int_equal( length, wildcard->length );
40
+
41
+ for (i = 0; i < length; i += 2) {
42
+ assert_int_equal((int)*(expected + i), (int)*(wildcard->first + i));
43
+ }
44
+
45
+ Wildcard_free(wildcard);
46
+ }
47
+
48
+
49
+ static void test_empty(state) // {{{1
50
+ void ** state;
51
+ {
52
+ Wildcard * wildcard;
53
+ int i;
54
+
55
+ wildcard = Wildcard_compile("", 0);
56
+ assert_int_not_equal( (int)NULL, (int)wildcard );
57
+ assert_int_equal( (int)NULL, (int)wildcard->first );
58
+ assert_int_equal( (int)NULL, (int)wildcard->last );
59
+ assert_int_equal( 0, wildcard->length );
60
+
61
+ Wildcard_free(wildcard);
62
+ }
63
+
64
+
65
+ static void test_fixed(state) // {{{1
66
+ void ** state;
67
+ {
68
+ const char expected[8] = {
69
+ Fixed, 'u',
70
+ Fixed, 'i',
71
+ Fixed, 'a',
72
+ Fixed, 'e',
73
+ };
74
+
75
+ generic_test("uiae", 8, expected);
76
+ }
77
+
78
+
79
+ static void test_group(state) // {{{1
80
+ void ** state;
81
+ {
82
+ const char expected[4] = {
83
+ Group, 'i',
84
+ Group, 'a',
85
+ };
86
+
87
+ generic_test("[ia]", 4, expected);
88
+ }
89
+
90
+
91
+ static void test_wild(state) // {{{1
92
+ void ** state;
93
+ {
94
+ const char expected[2] = {
95
+ Wild, '?',
96
+ };
97
+
98
+ generic_test("?", 2, expected);
99
+ }
100
+
101
+
102
+ static void test_kleene(state) // {{{1
103
+ void ** state;
104
+ {
105
+ const char expected[2] = {
106
+ Kleene, '*',
107
+ };
108
+
109
+ generic_test("*", 2, expected);
110
+ generic_test("**", 2, expected);
111
+ generic_test("****", 2, expected);
112
+ }
113
+
114
+
115
+ static void test_mixed(state) // {{{1
116
+ void ** state;
117
+ {
118
+ const char expected[10] = {
119
+ Fixed, 'u',
120
+ Wild, '?',
121
+ Kleene, '*',
122
+ Group, 'e',
123
+ Group, '?',
124
+ };
125
+
126
+ generic_test("u?*[e?]", 10, expected);
127
+ }
128
+
129
+
130
+ static void test_escaping(state) // {{{1
131
+ void ** state;
132
+ {
133
+ ruby_init(); // since we will be calling rb_warning
134
+
135
+ // escaping in fixed parts
136
+ {
137
+ char expected[4] = {
138
+ Fixed, '?',
139
+ Fixed, 'a',
140
+ };
141
+
142
+ // escaping of escapable characters
143
+ generic_test("\\?", 2, expected);
144
+
145
+ expected[1] = '*';
146
+ generic_test("\\*", 2, expected);
147
+
148
+ expected[1] = '[';
149
+ generic_test("\\[", 2, expected);
150
+
151
+ expected[1] = ']';
152
+ generic_test("\\]", 2, expected);
153
+
154
+ expected[1] = '\\';
155
+ generic_test("\\\\", 2, expected);
156
+
157
+ // special warning-generating escaping mechanism
158
+ expected[1] = ']';
159
+ generic_test("]", 2, expected);
160
+
161
+ // escaping of non-escapable characters
162
+ expected[1] = '\\';
163
+ generic_test("\\a", 4, expected);
164
+ }
165
+ // escaping in group parts
166
+ {
167
+ char expected[4] = {
168
+ Group, '[',
169
+ Group, 'a',
170
+ };
171
+
172
+ // escaping of escapable characters
173
+ generic_test("[\\[]", 2, expected);
174
+
175
+ expected[1] = ']';
176
+ generic_test("[\\]]", 2, expected);
177
+
178
+ expected[1] = '\\';
179
+ generic_test("[\\\\]", 2, expected);
180
+
181
+ // special warning-generating escaping mechanism
182
+ expected[1] = '[';
183
+ generic_test("[[]", 2, expected);
184
+
185
+ // escaping of non-escapable characters
186
+ expected[1] = '\\';
187
+ generic_test("[\\a]", 4, expected);
188
+
189
+ expected[3] = '?';
190
+ generic_test("[\\?]", 4, expected);
191
+ }
192
+ // escaping at EOS
193
+ {
194
+ char expected[4] = {
195
+ Fixed, '\\',
196
+ };
197
+
198
+ generic_test("\\", 2, expected);
199
+ }
200
+ }
201
+
202
+
203
+ int main() { // {{{1
204
+ const UnitTest tests[] = {
205
+ unit_test(test_empty),
206
+ unit_test(test_fixed),
207
+ unit_test(test_group),
208
+ unit_test(test_wild),
209
+ unit_test(test_kleene),
210
+ unit_test(test_mixed),
211
+ unit_test(test_escaping),
212
+ };
213
+ return run_tests(tests);
214
+ }
215
+