reg 0.4.6

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,318 @@
1
+
2
+ =begin copyright
3
+ reg - the ruby extended grammar
4
+ Copyright (C) 2005 Caleb Clausen
5
+
6
+ This library is free software; you can redistribute it and/or
7
+ modify it under the terms of the GNU Lesser General Public
8
+ License as published by the Free Software Foundation; either
9
+ version 2.1 of the License, or (at your option) any later version.
10
+
11
+ This library is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public
17
+ License along with this library; if not, write to the Free Software
18
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ =end
20
+
21
+
22
+ require 'forward_to'
23
+
24
+
25
+
26
+ module Reg
27
+
28
+ class Hash
29
+ include Reg
30
+ attr :others
31
+
32
+ def initialize(hashdat=nil)
33
+ @matchers={}
34
+ @literals={}
35
+ @others=nil
36
+ hashdat or return
37
+ hashdat.key?(OB) and @others=hashdat.delete(OB)
38
+ hashdat.each {|key,val|
39
+ if Reg.interesting_matcher? key
40
+ Fixed===key and key=key.unwrap
41
+ @matchers[key]=val
42
+ else
43
+ Equals===key and key=key.unwrap
44
+ @literals[key]=val
45
+ end
46
+ }
47
+ end
48
+
49
+ def Hash.[](*args); new(*args); end
50
+
51
+ def matches_class; ::Hash end
52
+
53
+ def ordered
54
+ pairs=[]
55
+ @literals.each{|k,v| pairs<< Pair[k,v] }
56
+ @matchers.each{|k,v| pairs<< Pair[k,v] }
57
+ pairs<<Pair[OB,@others] if @others
58
+ return +pairs
59
+ end
60
+
61
+ def subregs;
62
+ @literals.keys + @literals.values +
63
+ @matchers.keys + @matchers.values +
64
+ (@others==nil ? [OB,@others] : [])
65
+ end
66
+
67
+ def inspect
68
+ result=[]
69
+ result<<@literals.inspect.sub(/.(.*)./, "\\1") unless @literals.empty?
70
+ result<<@matchers.inspect.sub(/.(.*)./, "\\1") unless @matchers.empty?
71
+ result<<"OB=>#{@others.inspect}" if defined? @others and @others!=nil
72
+ return "+{#{result.join(", ")}}"
73
+ end
74
+
75
+ def -@ #make object matcher
76
+ Rob(@literals.merge(@matchers).merge(OB=>@others))
77
+ end
78
+
79
+ def ===(other)
80
+ matchedliterals={}
81
+ matchedmatchers={}
82
+ other.each_pair{|key,val|
83
+ #literals get a chance first
84
+ @literals.key? key and
85
+ if (@literals[key]===val)
86
+ matchedliterals[key]=true
87
+ next
88
+ else
89
+ return
90
+ end
91
+
92
+ #now try more general matchers
93
+ saw_matcher=nil
94
+ @matchers.each_pair{|mkey,mval|
95
+ if mkey===key
96
+ return unless (mval===val)
97
+ saw_matcher=matchedmatchers[mkey]=true
98
+ break
99
+ end
100
+ }
101
+
102
+
103
+ #last of all, try the catchall
104
+ saw_matcher or @others===val or return
105
+ }
106
+ @literals.each_pair{|k,v| matchedliterals[k] or v==(other.default k) or return }
107
+ @matchers.each_pair{|k,v| matchedmatchers[k] or v===other.default or return }
108
+ other.empty? and @literals.empty? and @matchers.empty? and return @others===other.default
109
+ return true
110
+ end
111
+
112
+ #tla of +{}
113
+ assign_TLAs :Rah=>:Hash
114
+
115
+ end
116
+
117
+ #--------------------------
118
+ class OrderedHash
119
+ include Reg
120
+ def initialize(*args)
121
+ @keys=[]
122
+ @vals=[]
123
+ @others=nil
124
+ args.each{|a|
125
+ if Pair===a
126
+ l,r=a.left,a.right
127
+ Fixed===l and l=l.unwrap
128
+ if l==OB
129
+ @others=r
130
+ else
131
+ @keys<<l
132
+ @vals<<r
133
+ end
134
+ else
135
+ @keys<<a
136
+ @vals<<OB
137
+ end
138
+ }
139
+ end
140
+
141
+ def ===(other)
142
+ matched=0
143
+ saw1=nil
144
+ other.each_pair do |ko,vo|
145
+ saw1=nil
146
+ @vals.each_index do|i|
147
+ kr,vr=@keys[i],@vals[i]
148
+ if kr===ko
149
+ vr===vo or return
150
+ saw1=matched |= 1<<i
151
+ break
152
+ end
153
+ end
154
+ saw1 or (@others===vo or return)
155
+ end
156
+ @vals.each_index {|i|
157
+ unless (matched&(1<<i)).nonzero?
158
+ @vals[i]===other.default((@keys[i] unless Reg::interesting_matcher? @keys[i])) or return
159
+ end
160
+ }
161
+ other.empty? and @vals.empty? and return @others===other.default
162
+ # @subhashes.each do|subhash|
163
+ # subhash===other or return false
164
+ # end
165
+ return other||true #huh need more complex result?
166
+ end
167
+
168
+ def self.[](*args); new(*args); end
169
+
170
+ def matches_class; ::Hash end
171
+
172
+ def &; huh end
173
+ def inspect;
174
+ "+[#{
175
+ map{|k,v| k.inspect+ ((Reg===k)? "" : ".reg") +
176
+ "**"+v.inspect unless OB==k && nil==v
177
+ }.compact.join ", "
178
+ }]"
179
+ end
180
+ def subregs; huh end
181
+
182
+ def each
183
+ @keys.each_index{|i|
184
+ yield @keys[i],@vals[i]
185
+ }
186
+ yield OB,@others
187
+ end
188
+ include Enumerable
189
+
190
+
191
+ def to_ruby
192
+ result= "def self.===(a_hash)\n"
193
+ result<<" a_hash.each_pair{|k,v|\n"
194
+ result<<" case k\n"
195
+ @keys.each_index{|i|
196
+ result<<" when #{@keys[i]}: #{vals[i]}\n"
197
+ }
198
+ result<<" else #{@other}\n" +
199
+ " end===v or break\n" +
200
+ " }\n" +
201
+ "end\n"
202
+
203
+ return result
204
+ end
205
+ end
206
+
207
+ #--------------------------
208
+ class Object < Hash
209
+ #decending from Hash isn't particularly useful here
210
+ #it looks like everything (but &) is overridden, anyway
211
+
212
+ def initialize(*args)
213
+ hash= (::Hash===args.last ? args.pop : {})
214
+ @vars={}; @meths={}; @meth_matchers={}
215
+ hash.each_pair{|item,val|
216
+ if ::String===item or ::Symbol===item
217
+ item=item.to_s
218
+ (/^@@?/===item ? @vars : @meths)[item.to_sym]=val
219
+ else
220
+ @meth_matchers[item]=val
221
+ end
222
+ }
223
+ @meths[:class]=args.shift if (Module===args.first)
224
+ end
225
+ def self.[](*args) new(*args); end
226
+
227
+
228
+ def inspect
229
+ "-{"+@vars.inspect.sub( /^.(.*).$/, '\\1') +
230
+ @meths.inspect.sub(/^.(.*).$/, '\\1') +
231
+ @meth_matchers.inspect.sub(/^.(.*).$/, '\\1') + "}"
232
+
233
+ end
234
+
235
+ def matches_class
236
+ @meths[:class] or Object
237
+ end
238
+
239
+ def -@ #make object matcher
240
+ self
241
+ end
242
+
243
+ def ===(other)
244
+ seenmeths=[];seenvars=[];seenmats=[]
245
+ @meths.each_pair{|name,val|
246
+ val===other.send(name) or return
247
+ seenmeths<<name
248
+ }
249
+ @vars.each_pair{|name,val|
250
+ val===other.instance_eval(name.to_s) or return
251
+ seenvars<<name
252
+ }
253
+ @meth_matchers.empty? or other.public_methods.each {|meth|
254
+ @meth_matchers.each_pair{|name, val|
255
+ if name===meth
256
+ val===other.send(meth) || return
257
+ seenmats<< name
258
+ end
259
+ }
260
+ }
261
+ @meths.keys.-(seenmeths).empty? or return
262
+ @vars.keys.-(seenvars).empty? or return
263
+ @meth_matchers.keys.-(seenmats).empty? or return
264
+
265
+
266
+ return other || true
267
+
268
+ rescue
269
+ return false
270
+ end
271
+
272
+ #tla of -{}
273
+ assign_TLAs :Rob=>:Object
274
+
275
+
276
+ end
277
+
278
+
279
+ #OrderedObject not even attempted yet
280
+
281
+ module Reg
282
+ def **(other)
283
+ Pair[self,other]
284
+ end
285
+ alias has **
286
+ end
287
+
288
+ class Pair
289
+ include Reg
290
+ class<<self; alias [] new; end
291
+
292
+ attr_reader :left,:right
293
+
294
+ def initialize(l,r)
295
+ @left,@right=l,r
296
+ end
297
+
298
+ if false #not sure if i know what i want here...
299
+ def hash_cmp(hash,k,v)
300
+ @left
301
+ end
302
+
303
+ def obj_cmp
304
+ end
305
+ end
306
+ #tla of **
307
+ assign_TLAs :Rap=>:Pair
308
+
309
+
310
+
311
+ end
312
+
313
+
314
+
315
+ end
316
+
317
+
318
+
@@ -0,0 +1,146 @@
1
+ =begin copyright
2
+ reg - the ruby extended grammar
3
+ Copyright (C) 2005 Caleb Clausen
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+ require 'regdeferred.rb'
20
+
21
+ module Reg
22
+ class <<self
23
+ #sugar forwards this from Kernel
24
+ def item_that(klass=nil,&block)
25
+ return ItemThat.new(klass) unless block
26
+
27
+ class <<block
28
+ #include arguments to include appear to be processed in a strange order... this is
29
+ #significant if order is important to you
30
+ #the #included methods are perhaps not called when i think they should be....
31
+ #(DON'T simplify the next line; it'll break.)
32
+ [BlankSlate ,Formula, BlockLike].each{|mod| include mod}
33
+ restore :inspect,:extend,:call
34
+
35
+ alias === eeee #workaround-- shouldn't be needed
36
+ alias formula_value call
37
+ # undef eeee
38
+ end
39
+ block.klass=klass
40
+ block
41
+ end
42
+ alias item_is item_that
43
+ end
44
+
45
+ #----------------------------------
46
+ module BlockLike
47
+ # include Formula
48
+
49
+ attr_writer :klass #for internal use only
50
+
51
+ def eeee(val)
52
+ @klass and @klass===val || return
53
+ begin call(val)
54
+ rescue: false
55
+ end
56
+ end
57
+ alias === eeee #does nothing in includers.... why?
58
+ def formula_value *a,&b; call( *a,&b) end
59
+
60
+
61
+ def mixmod; ItemThatLike end
62
+ def reg; dup.extend Reg end
63
+ end
64
+
65
+ #----------------------------------
66
+ module DeferredQuery
67
+ #just an ancestor for ItemThat and RegThat
68
+ def eee(item)
69
+ begin formula_value item
70
+ rescue: false
71
+ end
72
+ end
73
+ alias === eee #this doesn't work!!! WHY????
74
+ #there's no way to define the method === in this
75
+ #module and have it be defined in class ItemThat.
76
+ #mixmod and reg don't have this problem. this must
77
+ #be a bug. for now, I work around it with clever
78
+ #alias/undefing in places that include/extend ItemThatLike
79
+ #(seemingly, this is only a problem when including, not extending... dunno why)
80
+ #this bug may be gone now; need to try to get rid of weird eee stuff.
81
+
82
+ end
83
+
84
+ #----------------------------------
85
+ module ItemThatLike
86
+ include DeferredQuery
87
+
88
+ def mixmod; ItemThatLike end
89
+ def reg; dup.extend RegThatLike end
90
+ end
91
+
92
+ #----------------------------------
93
+ class ItemThat
94
+ include BlankSlate
95
+ restore :inspect,:extend
96
+ include Formula
97
+ include ItemThatLike
98
+ alias === eee
99
+ undef eee
100
+ def initialize(klass=nil)
101
+ @klass=klass
102
+ end
103
+
104
+ def formula_value(val,*rest)
105
+ #the exception raised here should be (eventually) caught by
106
+ #the handler in ItemThatLike#eee. calling ItemThat#formula_value isn't
107
+ #really legitimate otherwise.
108
+ @klass and @klass===val || fail("item_that constraint mismatch")
109
+
110
+ val
111
+ end
112
+
113
+ end
114
+
115
+ #----------------------------------
116
+ module RegThatLike
117
+ include DeferredQuery
118
+ include Reg
119
+
120
+ def mixmod; RegThatLike end
121
+ end
122
+
123
+ #----------------------------------
124
+ class RegThat
125
+ include BlankSlate
126
+ restore :inspect,:extend
127
+ include Formula
128
+ include RegThatLike
129
+ alias === eee
130
+ undef eee
131
+ def initialize(klass=nil)
132
+ @klass=klass
133
+ end
134
+
135
+ def formula_value(val,*rest)
136
+ #the exception raised here should be (eventually) caught by
137
+ #the handler in RegThatLike#eee. calling RegThat#formula_value isn't
138
+ #really legitimate otherwise.
139
+ @klass and @klass===val || fail("item_that constraint mismatch")
140
+
141
+ val
142
+ end
143
+
144
+ end
145
+
146
+ end