joker 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+