openwferu-extras 0.9.12.863
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/openwfe/extras/listeners/sqslisteners.rb +151 -0
- data/lib/openwfe/extras/participants/activeparticipants.rb +334 -0
- data/lib/openwfe/extras/participants/atomparticipants.rb +198 -0
- data/lib/openwfe/extras/participants/csvparticipants.rb +129 -0
- data/lib/openwfe/extras/participants/sqsparticipants.rb +124 -0
- data/lib/openwfe/extras/participants/twitterparticipants.rb +191 -0
- data/lib/openwfe/extras/util/csvtable.rb +448 -0
- data/lib/openwfe/extras/util/sqs.rb +581 -0
- metadata +56 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
#
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2007, John Mettraux, OpenWFE.org
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# . Redistributions of source code must retain the above copyright notice, this
|
10
|
+
# list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# . Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
|
17
|
+
# used to endorse or promote products derived from this software without
|
18
|
+
# specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#++
|
32
|
+
#
|
33
|
+
|
34
|
+
#
|
35
|
+
# "made in Japan"
|
36
|
+
#
|
37
|
+
# John Mettraux at openwfe.org
|
38
|
+
#
|
39
|
+
|
40
|
+
#
|
41
|
+
# this participant requires the twitter4r gem
|
42
|
+
#
|
43
|
+
# http://rubyforge.org/projects/twitter4r/
|
44
|
+
#
|
45
|
+
# atom-tools' license is X11/MIT
|
46
|
+
#
|
47
|
+
|
48
|
+
require 'rubygems'
|
49
|
+
|
50
|
+
begin
|
51
|
+
#gem 'twitter4r', '0.2.3'
|
52
|
+
require 'twitter'
|
53
|
+
rescue LoadError
|
54
|
+
#
|
55
|
+
# soft dependency on 'atom-tools'
|
56
|
+
#
|
57
|
+
puts
|
58
|
+
puts
|
59
|
+
puts "'twitter4r' is missing. You can install it with :"
|
60
|
+
puts
|
61
|
+
puts " [sudo] gem install -y twitter4r"
|
62
|
+
puts
|
63
|
+
puts
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'openwfe/utils'
|
68
|
+
require 'openwfe/participants/participant'
|
69
|
+
|
70
|
+
|
71
|
+
module OpenWFE
|
72
|
+
module Extras
|
73
|
+
|
74
|
+
#
|
75
|
+
# Sometimes email is a bit too heavy for notification, this participant
|
76
|
+
# emit messages via a twitter account.
|
77
|
+
#
|
78
|
+
# By default, the message emitted is the value of the field
|
79
|
+
# "twitter_message", but this behaviour can be changed by overriding
|
80
|
+
# the extract_message() method.
|
81
|
+
#
|
82
|
+
# If the extract_message doesn't find a message, the message will
|
83
|
+
# be the result of the default_message method call, of course this
|
84
|
+
# method is overridable as well.
|
85
|
+
#
|
86
|
+
class TwitterParticipant
|
87
|
+
include OpenWFE::LocalParticipant
|
88
|
+
|
89
|
+
#
|
90
|
+
# The actual twitter4r client instance.
|
91
|
+
#
|
92
|
+
attr_accessor :client
|
93
|
+
|
94
|
+
#
|
95
|
+
# Keeping the initialization params at hand (if any)
|
96
|
+
#
|
97
|
+
attr_accessor :params
|
98
|
+
|
99
|
+
#
|
100
|
+
# This participant expects a login (twitter user name) and a password.
|
101
|
+
#
|
102
|
+
# The only optional param for now is :no_ssl, which you can set to
|
103
|
+
# true if you want the connection to twitter to not use SSL.
|
104
|
+
# (seems like the Twitter SSL service is available less often
|
105
|
+
# than the plain http one).
|
106
|
+
#
|
107
|
+
def initialize (login, password, params={})
|
108
|
+
|
109
|
+
super()
|
110
|
+
|
111
|
+
Twitter::Client.configure do |conf|
|
112
|
+
conf.protocol = :http
|
113
|
+
conf.port = 80
|
114
|
+
end if params[:no_ssl] == true
|
115
|
+
|
116
|
+
@client = Twitter::Client.new(
|
117
|
+
:login => login,
|
118
|
+
:password => password)
|
119
|
+
|
120
|
+
@params = params
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# The method called by the engine when a workitem for this
|
125
|
+
# participant is available.
|
126
|
+
#
|
127
|
+
def consume (workitem)
|
128
|
+
|
129
|
+
user, tmessage = extract_message workitem
|
130
|
+
|
131
|
+
tmessage = default_message(workitem) unless tmessage
|
132
|
+
|
133
|
+
begin
|
134
|
+
|
135
|
+
if user
|
136
|
+
#
|
137
|
+
# direct message
|
138
|
+
#
|
139
|
+
tuser = @client.user user.to_s
|
140
|
+
@client.message :post, tmessage, tuser
|
141
|
+
else
|
142
|
+
#
|
143
|
+
# just the classical status
|
144
|
+
#
|
145
|
+
@client.status :post, tmessage
|
146
|
+
end
|
147
|
+
|
148
|
+
rescue Exception => e
|
149
|
+
|
150
|
+
linfo do
|
151
|
+
"consume() not emitted twitter, because of " +
|
152
|
+
OpenWFE::exception_to_s(e)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
reply_to_engine(workitem) if @application_context
|
157
|
+
end
|
158
|
+
|
159
|
+
protected
|
160
|
+
|
161
|
+
#
|
162
|
+
# Returns a pair : the target user (twitter login name)
|
163
|
+
# and the message (or status message if there is no target user) to
|
164
|
+
# send to Twitter.
|
165
|
+
#
|
166
|
+
# This default implementation returns a pair composed with the
|
167
|
+
# values of the field 'twitter_target' and of the field
|
168
|
+
# 'twitter_message'.
|
169
|
+
#
|
170
|
+
def extract_message (workitem)
|
171
|
+
|
172
|
+
[ workitem.attributes['twitter_target'],
|
173
|
+
workitem.attributes['twitter_message'] ]
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Returns the default message (called when the extract_message
|
178
|
+
# returned nil as the second element of its pair).
|
179
|
+
#
|
180
|
+
# This default implementation simply returns the workitem
|
181
|
+
# FlowExpressionId instance in its to_s() representation.
|
182
|
+
#
|
183
|
+
def default_message (workitem)
|
184
|
+
|
185
|
+
workitem.fei.to_s
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
@@ -0,0 +1,448 @@
|
|
1
|
+
#
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2007, John Mettraux, OpenWFE.org
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# . Redistributions of source code must retain the above copyright notice, this
|
10
|
+
# list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# . Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
|
17
|
+
# used to endorse or promote products derived from this software without
|
18
|
+
# specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#++
|
32
|
+
#
|
33
|
+
|
34
|
+
#
|
35
|
+
# "made in Japan"
|
36
|
+
#
|
37
|
+
# John Mettraux at openwfe.org
|
38
|
+
#
|
39
|
+
|
40
|
+
require 'csv'
|
41
|
+
|
42
|
+
require 'openwfe/utils'
|
43
|
+
require 'openwfe/util/dollar'
|
44
|
+
|
45
|
+
include OpenWFE
|
46
|
+
|
47
|
+
|
48
|
+
module OpenWFE
|
49
|
+
module Extras
|
50
|
+
|
51
|
+
#
|
52
|
+
# A 'CsvTable' is called a 'decision table' in OpenWFEja (the initial
|
53
|
+
# Java implementation of OpenWFE).
|
54
|
+
#
|
55
|
+
# A csv table is a description of a set of rules as a CSV (comma
|
56
|
+
# separated values) file. Such a file can be edited / generated by
|
57
|
+
# a spreadsheet (Excel, Google spreadsheets, Gnumeric, ...)
|
58
|
+
#
|
59
|
+
# The following CSV file
|
60
|
+
#
|
61
|
+
# in:topic,in:region,out:team_member
|
62
|
+
# sports,europe,Alice
|
63
|
+
# sports,,Bob
|
64
|
+
# finance,america,Charly
|
65
|
+
# finance,europe,Donald
|
66
|
+
# finance,,Ernest
|
67
|
+
# politics,asia,Fujio
|
68
|
+
# politics,america,Gilbert
|
69
|
+
# politics,,Henry
|
70
|
+
# ,,Zach
|
71
|
+
#
|
72
|
+
# embodies a rule for distributing items (piece of news) labelled with a
|
73
|
+
# topic and a region to various members of a team.
|
74
|
+
# For example, all news about finance from Europe are to be routed to
|
75
|
+
# Donald.
|
76
|
+
#
|
77
|
+
# Evaluation occurs row by row. The "in out" row states which field
|
78
|
+
# is considered at input and which are to be modified if the "ins" do
|
79
|
+
# match.
|
80
|
+
#
|
81
|
+
# The default behaviour is to change the value of the "outs" if all the
|
82
|
+
# "ins" match and then terminate.
|
83
|
+
# An empty "in" cell means "matches any".
|
84
|
+
#
|
85
|
+
# Enough words, some code :
|
86
|
+
#
|
87
|
+
# table = CsvTable.new("""
|
88
|
+
# in:topic,in:region,out:team_member
|
89
|
+
# sports,europe,Alice
|
90
|
+
# sports,,Bob
|
91
|
+
# finance,america,Charly
|
92
|
+
# finance,europe,Donald
|
93
|
+
# finance,,Ernest
|
94
|
+
# politics,asia,Fujio
|
95
|
+
# politics,america,Gilbert
|
96
|
+
# politics,,Henry
|
97
|
+
# ,,Zach
|
98
|
+
# """)
|
99
|
+
#
|
100
|
+
# h = {}
|
101
|
+
# h["topic"] = "politics"
|
102
|
+
#
|
103
|
+
# table.transform(h)
|
104
|
+
#
|
105
|
+
# puts h["team_member"]
|
106
|
+
# # will yield "Henry" who takes care of all the politics stuff,
|
107
|
+
# # except for Asia and America
|
108
|
+
#
|
109
|
+
# '>', '>=', '<' and '<=' can be put in front of individual cell values :
|
110
|
+
#
|
111
|
+
# table = CsvTable.new("""
|
112
|
+
# ,
|
113
|
+
# in:fx, out:fy
|
114
|
+
# ,
|
115
|
+
# >100,a
|
116
|
+
# >=10,b
|
117
|
+
# ,c
|
118
|
+
# """)
|
119
|
+
#
|
120
|
+
# h = { 'fx' => '10' }
|
121
|
+
# table.transform(h)
|
122
|
+
#
|
123
|
+
# require 'pp'; pp h
|
124
|
+
# # will yield { 'fx' => '10', 'fy' => 'b' }
|
125
|
+
#
|
126
|
+
# Such comparisons are done after the elements are transformed to float
|
127
|
+
# numbers. By default, non-numeric arguments will get compared as Strings.
|
128
|
+
#
|
129
|
+
#
|
130
|
+
# Disclaimer : the decision / CSV table system is no replacement for
|
131
|
+
# full rule engines with forward and backward chaining, RETE implementation
|
132
|
+
# and the like...
|
133
|
+
#
|
134
|
+
#
|
135
|
+
# Options :
|
136
|
+
#
|
137
|
+
# You can put options on their own in a cell BEFORE the line containing
|
138
|
+
# "in:xxx" and "out:yyy" (ins and outs).
|
139
|
+
#
|
140
|
+
# Currently, two options are supported, "ignorecase" and "through".
|
141
|
+
#
|
142
|
+
# "ignorecase", if found by the CsvTable will make any match (in the "in"
|
143
|
+
# columns) case unsensitive.
|
144
|
+
#
|
145
|
+
# "through", will make sure that EVERY row is evaluated and potentially
|
146
|
+
# applied. The default behaviour (without "through"), is to stop the
|
147
|
+
# evaluation after applying the results of the first matching row.
|
148
|
+
#
|
149
|
+
#
|
150
|
+
# CSV Tables are available to workflows as CsvParticipant.
|
151
|
+
#
|
152
|
+
#
|
153
|
+
# See also :
|
154
|
+
#
|
155
|
+
# http://jmettraux.wordpress.com/2007/02/11/ruby-decision-tables/
|
156
|
+
# http://rubyforge.org/viewvc/trunk/openwfe-ruby/test/extras/csv_test.rb?root=openwferu&view=co
|
157
|
+
#
|
158
|
+
class CsvTable
|
159
|
+
|
160
|
+
attr_accessor \
|
161
|
+
:first_match,
|
162
|
+
:ignore_case,
|
163
|
+
:header,
|
164
|
+
:rows
|
165
|
+
|
166
|
+
#
|
167
|
+
# The constructor for CsvTable, you can pass a String, an Array
|
168
|
+
# (of arrays), a File object. The CSV parser coming with Ruby will take
|
169
|
+
# care of it and a CsvTable instance will be built.
|
170
|
+
#
|
171
|
+
def initialize (csv_data)
|
172
|
+
|
173
|
+
@first_match = true
|
174
|
+
@ignore_case = false
|
175
|
+
|
176
|
+
@header = nil
|
177
|
+
@rows = []
|
178
|
+
|
179
|
+
csv_array = to_csv_array(csv_data)
|
180
|
+
|
181
|
+
csv_array.each do |row|
|
182
|
+
|
183
|
+
next if empty_row? row
|
184
|
+
|
185
|
+
if @header
|
186
|
+
#@rows << row
|
187
|
+
@rows << row.collect { |c| c.strip if c }
|
188
|
+
else
|
189
|
+
parse_header_row(row)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# Returns the workitem massaged by the csv table
|
196
|
+
#
|
197
|
+
def transform_wi (flow_expression, workitem)
|
198
|
+
|
199
|
+
@rows.each do |row|
|
200
|
+
|
201
|
+
if matches?(row, flow_expression, workitem)
|
202
|
+
apply(row, flow_expression, workitem)
|
203
|
+
break if @first_match
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
return workitem
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Passes a simple Hash instance though the csv table
|
212
|
+
#
|
213
|
+
def transform (hash)
|
214
|
+
wi = InFlowWorkItem.new()
|
215
|
+
wi.attributes = hash
|
216
|
+
return transform_wi(nil, wi).attributes
|
217
|
+
end
|
218
|
+
|
219
|
+
protected
|
220
|
+
|
221
|
+
def to_csv_array (csv_data)
|
222
|
+
|
223
|
+
return csv_data if csv_data.kind_of? Array
|
224
|
+
return CSV::Reader.parse(csv_data)
|
225
|
+
end
|
226
|
+
|
227
|
+
def matches? (row, fexp, wi)
|
228
|
+
|
229
|
+
return false if empty_row? row
|
230
|
+
|
231
|
+
#puts
|
232
|
+
#puts "__row match ?"
|
233
|
+
#require 'pp'
|
234
|
+
#pp row
|
235
|
+
|
236
|
+
@header.ins.each_with_index do |in_header, icol|
|
237
|
+
|
238
|
+
in_header = resolve_in_header(in_header)
|
239
|
+
|
240
|
+
value = OpenWFE::dosub(in_header, fexp, wi)
|
241
|
+
|
242
|
+
cell = row[icol]
|
243
|
+
|
244
|
+
next if not cell
|
245
|
+
|
246
|
+
cell = cell.strip
|
247
|
+
|
248
|
+
next if cell.length < 1
|
249
|
+
|
250
|
+
cell = OpenWFE::dosub(cell, fexp, wi)
|
251
|
+
|
252
|
+
#puts "__does '#{value}' match '#{cell}' ?"
|
253
|
+
|
254
|
+
b = if cell[0, 1] == '<' or cell[0, 1] == '>'
|
255
|
+
numeric_compare(value, cell)
|
256
|
+
else
|
257
|
+
regex_compare(value, cell)
|
258
|
+
end
|
259
|
+
|
260
|
+
return false unless b
|
261
|
+
end
|
262
|
+
|
263
|
+
#puts "__row matches"
|
264
|
+
|
265
|
+
return true
|
266
|
+
end
|
267
|
+
|
268
|
+
def regex_compare (value, cell)
|
269
|
+
|
270
|
+
modifiers = 0
|
271
|
+
modifiers += Regexp::IGNORECASE if @ignore_case
|
272
|
+
|
273
|
+
rcell = Regexp.new(cell, modifiers)
|
274
|
+
|
275
|
+
rcell.match(value)
|
276
|
+
end
|
277
|
+
|
278
|
+
def numeric_compare (value, cell)
|
279
|
+
|
280
|
+
comparator = cell[0, 1]
|
281
|
+
comparator += "=" if cell[1, 1] == "="
|
282
|
+
cell = cell[comparator.length..-1]
|
283
|
+
|
284
|
+
nvalue = narrow(value)
|
285
|
+
ncell = narrow(cell)
|
286
|
+
|
287
|
+
if nvalue.is_a? String or ncell.is_a? String
|
288
|
+
value = '"' + value + '"'
|
289
|
+
cell = '"' + cell + '"'
|
290
|
+
else
|
291
|
+
value = nvalue
|
292
|
+
cell = ncell
|
293
|
+
end
|
294
|
+
|
295
|
+
s = "#{value} #{comparator} #{cell}"
|
296
|
+
|
297
|
+
#puts "...>>>#{s}<<<"
|
298
|
+
|
299
|
+
begin
|
300
|
+
return OpenWFE::eval_safely(s, 4)
|
301
|
+
rescue Exception => e
|
302
|
+
return false
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def narrow (s)
|
307
|
+
begin
|
308
|
+
return Float(s)
|
309
|
+
rescue Exception => e
|
310
|
+
return s
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def resolve_in_header (in_header)
|
315
|
+
|
316
|
+
in_header = "f:#{in_header}" \
|
317
|
+
if points_to_nothing? in_header
|
318
|
+
|
319
|
+
return "${#{in_header}}"
|
320
|
+
end
|
321
|
+
|
322
|
+
def apply (row, fexp, wi)
|
323
|
+
|
324
|
+
#puts "__ apply() wi.class : #{wi.class.name}"
|
325
|
+
|
326
|
+
@header.outs.each_with_index do |out_header, icol|
|
327
|
+
|
328
|
+
next unless out_header
|
329
|
+
|
330
|
+
value = row[icol]
|
331
|
+
|
332
|
+
next unless value
|
333
|
+
#next unless value.strip.length > 0
|
334
|
+
next unless value.length > 0
|
335
|
+
|
336
|
+
value = OpenWFE::dosub(value, fexp, wi)
|
337
|
+
|
338
|
+
#puts "___ value:'#{value}'"
|
339
|
+
#puts "___ value:'"+value+"'"
|
340
|
+
|
341
|
+
type, target = points_at(out_header)
|
342
|
+
|
343
|
+
#puts "___ t:'#{type}' target:'#{target}'"
|
344
|
+
|
345
|
+
if type == "v"
|
346
|
+
fexp.set_variable(target, value) if fexp
|
347
|
+
elsif type == "f"
|
348
|
+
wi.set_attribute(target, value)
|
349
|
+
elsif type == "r"
|
350
|
+
#instance_eval(value)
|
351
|
+
OpenWFE::instance_eval_safely(self, value, 3)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def parse_header_row (row)
|
357
|
+
|
358
|
+
row.each_with_index do |cell, icol|
|
359
|
+
|
360
|
+
next unless cell
|
361
|
+
|
362
|
+
cell = cell.strip
|
363
|
+
s = cell.downcase
|
364
|
+
|
365
|
+
if s == "ignorecase" or s == "ignore_case"
|
366
|
+
@ignore_case = true
|
367
|
+
next
|
368
|
+
end
|
369
|
+
|
370
|
+
if s == "through"
|
371
|
+
@first_match = false
|
372
|
+
next
|
373
|
+
end
|
374
|
+
|
375
|
+
if OpenWFE::starts_with(cell, "in:") or OpenWFE::starts_with(cell, "out:")
|
376
|
+
@header = Header.new unless @header
|
377
|
+
@header.add cell, icol
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def empty_row? (row)
|
383
|
+
return true unless row
|
384
|
+
return true if (row.length == 1 and not row[0])
|
385
|
+
row.each do |cell|
|
386
|
+
return false if cell
|
387
|
+
end
|
388
|
+
return true
|
389
|
+
end
|
390
|
+
|
391
|
+
def points_to_nothing? (label)
|
392
|
+
(not points_to_variable? label) and \
|
393
|
+
(not points_to_field? label) and \
|
394
|
+
(not points_to_ruby? label)
|
395
|
+
end
|
396
|
+
def points_at (label)
|
397
|
+
v = points_to_variable? label
|
398
|
+
return "v", v if v
|
399
|
+
r = points_to_ruby? label
|
400
|
+
return "r", r if r
|
401
|
+
f = points_to_field? label
|
402
|
+
return "f", f if f
|
403
|
+
return "f", label # else
|
404
|
+
end
|
405
|
+
def points_to_variable? (label)
|
406
|
+
points_to?(label, [ "v", "var", "variable" ])
|
407
|
+
end
|
408
|
+
def points_to_field? (label)
|
409
|
+
points_to?(label, [ "f", "field" ])
|
410
|
+
end
|
411
|
+
def points_to_ruby? (label)
|
412
|
+
points_to?(label, [ "r", "ruby", "reval" ])
|
413
|
+
end
|
414
|
+
def points_to? (label, names)
|
415
|
+
i = label.index(":")
|
416
|
+
return nil unless i
|
417
|
+
s = label[0..i-1]
|
418
|
+
names.each do |name|
|
419
|
+
return label[i+1..-1] if s == name
|
420
|
+
end
|
421
|
+
return nil
|
422
|
+
end
|
423
|
+
|
424
|
+
class Header
|
425
|
+
|
426
|
+
attr_accessor :ins, :outs
|
427
|
+
|
428
|
+
def initialize
|
429
|
+
@ins = []
|
430
|
+
@outs = []
|
431
|
+
end
|
432
|
+
|
433
|
+
def add (cell, icol)
|
434
|
+
if OpenWFE::starts_with(cell, "in:")
|
435
|
+
@ins[icol] = cell[3..-1]
|
436
|
+
#puts "i added #{@ins[icol]}"
|
437
|
+
elsif OpenWFE::starts_with(cell, "out:")
|
438
|
+
@outs[icol] = cell[4..-1]
|
439
|
+
#puts "o added #{@outs[icol]}"
|
440
|
+
end
|
441
|
+
# else don't add
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|