amanzi-sld 0.0.1

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,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script uses the amanzi-sld DSL to create a sample SLD file
4
+ # containing a few examples. The examples are done in a few different
5
+ # ways to demonstrate the SLD syntax.
6
+
7
+ require 'amanzi/sld'
8
+
9
+ Amanzi::SLD::Config.config[:geometry_property] = 'the_geom'
10
+ #Amanzi::SLD::Config.config[:verbose] = true
11
+
12
+ sld = Amanzi::SLD::Document.new "Example"
13
+
14
+ # Create XML using the underlying pure-XML DSL from Amanzi::XML
15
+ sld.comment "Pure-XML DSL"
16
+ sld.feature_type_style.rule.line_symbolizer.stroke do |stroke|
17
+ stroke.css_parameter(:name => "stroke") << '#dddddd'
18
+ stroke.css_parameter(:name => "stroke-width") << '1'
19
+ end
20
+
21
+ # Now create some SLD XML using the higher level SLD-specific syntax
22
+
23
+ # First a simple example, a LineSymbolizer with no filter
24
+ sld.comment "Simple Line DSL"
25
+ sld.add_line_symbolizer(:stroke_width => 2, :stroke => '#dddddd')
26
+
27
+ # Now try one with a filter, but specified using XML DSL
28
+ sld.comment "Line with Filter, using XML DSL"
29
+ sld.feature_type_style.rule do |rule|
30
+ rule.filter.ns(:ogc).property_is_equal_to do |f|
31
+ f.function(:name => 'geometryType').property_name << 'the_geom'
32
+ f.literal << 'Polygon'
33
+ end
34
+ rule.polygon_symbolizer do |s|
35
+ s.fill do |f|
36
+ f.css_parameter(:name=>"fill") << '#aaaaaa'
37
+ f.css_parameter(:name=>"fill-opacity") << '0.4'
38
+ end
39
+ s.stroke.css_parameter(:name => "stroke") << '#ffe0e0'
40
+ end
41
+ end
42
+
43
+ # And now see how simple these can be with the SLD syntax
44
+ sld.comment "Line with Filter, using SLD DSL"
45
+ sld.add_line_symbolizer(:stroke_width => 2, :stroke => '#dddddd') do |f|
46
+ f.geometry = 'LineString'
47
+ end
48
+ sld.comment "Polygon with Filter, using SLD DSL"
49
+ sld.add_polygon_symbolizer(:stroke_width => 2, :stroke => '#dddddd', :fill => '#aaaaaa', :fill_opacity => 0.4) do |f|
50
+ f.geometry = 'Polygon'
51
+ end
52
+ sld.comment "Polygon with Filter, using SLD DSL, and more compact polygon filtering syntax"
53
+ sld.add_polygon_symbolizer(:stroke_width => 2, :stroke => '#dddddd', :fill => '#aaaaaa', :fill_opacity => 0.4, :geometry => 'Polygon')
54
+
55
+ # Using SLD syntax for Filtering makes it simler to do really complex things
56
+ sld.comment "Polygon with complex Filter"
57
+ sld.add_polygon_symbolizer(:stroke_width => 2, :stroke => '#dddddd', :fill => '#aaaaaa', :fill_opacity => 0.4) do |f|
58
+ f.op(:and) do |f|
59
+ f.geometry = 'Polygon'
60
+ f.op(:or) do |f|
61
+ f.property.not_exists? :highway
62
+ f.property.exists? :waterway
63
+ f.property[:natural] = 'water'
64
+ end
65
+ end
66
+ end
67
+
68
+ # Combining the compact geometry option with other filter settings
69
+ sld.comment "Polygon with combined simple and complex Filter"
70
+ sld.add_polygon_symbolizer(:stroke_width => 2, :stroke => '#dddddd', :fill => '#aaaaaa', :fill_opacity => 0.4, :geometry => 'Polygon') do |f|
71
+ f.op(:or) do |f|
72
+ f.property.not_exists? :highway
73
+ f.property.exists? :waterway
74
+ f.property[:natural] = 'water'
75
+ end
76
+ end
77
+
78
+ # Adding a set of symbolizers within the same rules filter
79
+ sld.comment "Multiple symbolizers and complex filter"
80
+ sld.
81
+ add_line_symbolizer(:stroke_width => 7, :stroke => '#303030').
82
+ add_line_symbolizer(:stroke_width => 5, :stroke => '#e0e0ff') do |f|
83
+ f.op(:and) do |f|
84
+ f.property.exists? :highway
85
+ f.op(:or) do |f|
86
+ f.property[:highway] = 'secondary'
87
+ f.property[:highway] = 'tertiary'
88
+ end
89
+ end
90
+ end
91
+
92
+ puts sld.to_xml(:tab => ' ')
93
+
94
+ #HTML::Document.test
95
+
@@ -0,0 +1,232 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <StyledLayerDescriptor xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" xmlns:ogc="http://www.opengis.net/ogc" version="1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/sld">
3
+ <NamedLayer>
4
+ <Name>Example</Name>
5
+ <UserStyle>
6
+ <Name>Example</Name>
7
+ <!-- Pure-XML DSL -->
8
+ <FeatureTypeStyle>
9
+ <Rule>
10
+ <LineSymbolizer>
11
+ <Stroke>
12
+ <CssParameter name="stroke">#dddddd</CssParameter>
13
+ <CssParameter name="stroke-width">1</CssParameter>
14
+ </Stroke>
15
+ </LineSymbolizer>
16
+ </Rule>
17
+ </FeatureTypeStyle>
18
+ <!-- Simple Line DSL -->
19
+ <FeatureTypeStyle>
20
+ <Rule>
21
+ <LineSymbolizer>
22
+ <Stroke>
23
+ <CssParameter name="stroke-width">2</CssParameter>
24
+ <CssParameter name="stroke">#dddddd</CssParameter>
25
+ </Stroke>
26
+ </LineSymbolizer>
27
+ </Rule>
28
+ </FeatureTypeStyle>
29
+ <!-- Line with Filter, using XML DSL -->
30
+ <FeatureTypeStyle>
31
+ <Rule>
32
+ <ogc:Filter>
33
+ <ogc:PropertyIsEqualTo>
34
+ <ogc:Function name="geometryType">
35
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
36
+ </ogc:Function>
37
+ <ogc:Literal>Polygon</ogc:Literal>
38
+ </ogc:PropertyIsEqualTo>
39
+ </ogc:Filter>
40
+ <PolygonSymbolizer>
41
+ <Fill>
42
+ <CssParameter name="fill">#aaaaaa</CssParameter>
43
+ <CssParameter name="fill-opacity">0.4</CssParameter>
44
+ </Fill>
45
+ <Stroke>
46
+ <CssParameter name="stroke">#ffe0e0</CssParameter>
47
+ </Stroke>
48
+ </PolygonSymbolizer>
49
+ </Rule>
50
+ </FeatureTypeStyle>
51
+ <!-- Line with Filter, using SLD DSL -->
52
+ <FeatureTypeStyle>
53
+ <Rule>
54
+ <ogc:Filter>
55
+ <ogc:PropertyIsEqualTo>
56
+ <ogc:Function name="geometryType">
57
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
58
+ </ogc:Function>
59
+ <ogc:Literal>LineString</ogc:Literal>
60
+ </ogc:PropertyIsEqualTo>
61
+ </ogc:Filter>
62
+ <LineSymbolizer>
63
+ <Stroke>
64
+ <CssParameter name="stroke-width">2</CssParameter>
65
+ <CssParameter name="stroke">#dddddd</CssParameter>
66
+ </Stroke>
67
+ </LineSymbolizer>
68
+ </Rule>
69
+ </FeatureTypeStyle>
70
+ <!-- Polygon with Filter, using SLD DSL -->
71
+ <FeatureTypeStyle>
72
+ <Rule>
73
+ <ogc:Filter>
74
+ <ogc:PropertyIsEqualTo>
75
+ <ogc:Function name="geometryType">
76
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
77
+ </ogc:Function>
78
+ <ogc:Literal>Polygon</ogc:Literal>
79
+ </ogc:PropertyIsEqualTo>
80
+ </ogc:Filter>
81
+ <PolygonSymbolizer>
82
+ <Fill>
83
+ <CssParameter name="fill-opacity">0.4</CssParameter>
84
+ <CssParameter name="fill">#aaaaaa</CssParameter>
85
+ </Fill>
86
+ <Stroke>
87
+ <CssParameter name="stroke-width">2</CssParameter>
88
+ <CssParameter name="stroke">#dddddd</CssParameter>
89
+ </Stroke>
90
+ </PolygonSymbolizer>
91
+ </Rule>
92
+ </FeatureTypeStyle>
93
+ <!-- Polygon with Filter, using SLD DSL, and more compact polygon filtering syntax -->
94
+ <FeatureTypeStyle>
95
+ <Rule>
96
+ <ogc:Filter>
97
+ <ogc:PropertyIsEqualTo>
98
+ <ogc:Function name="geometryType">
99
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
100
+ </ogc:Function>
101
+ <ogc:Literal>Polygon</ogc:Literal>
102
+ </ogc:PropertyIsEqualTo>
103
+ </ogc:Filter>
104
+ <PolygonSymbolizer>
105
+ <Fill>
106
+ <CssParameter name="fill-opacity">0.4</CssParameter>
107
+ <CssParameter name="fill">#aaaaaa</CssParameter>
108
+ </Fill>
109
+ <Stroke>
110
+ <CssParameter name="stroke-width">2</CssParameter>
111
+ <CssParameter name="stroke">#dddddd</CssParameter>
112
+ </Stroke>
113
+ </PolygonSymbolizer>
114
+ </Rule>
115
+ </FeatureTypeStyle>
116
+ <!-- Polygon with complex Filter -->
117
+ <FeatureTypeStyle>
118
+ <Rule>
119
+ <ogc:Filter>
120
+ <ogc:And>
121
+ <ogc:PropertyIsEqualTo>
122
+ <ogc:Function name="geometryType">
123
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
124
+ </ogc:Function>
125
+ <ogc:Literal>Polygon</ogc:Literal>
126
+ </ogc:PropertyIsEqualTo>
127
+ <ogc:Or>
128
+ <ogc:PropertyIsNull>
129
+ <ogc:PropertyName>highway</ogc:PropertyName>
130
+ </ogc:PropertyIsNull>
131
+ <ogc:Not>
132
+ <ogc:PropertyIsNull>
133
+ <ogc:PropertyName>waterway</ogc:PropertyName>
134
+ </ogc:PropertyIsNull>
135
+ </ogc:Not>
136
+ <ogc:PropertyIsEqualTo>
137
+ <ogc:PropertyName>natural</ogc:PropertyName>
138
+ <ogc:Literal>water</ogc:Literal>
139
+ </ogc:PropertyIsEqualTo>
140
+ </ogc:Or>
141
+ </ogc:And>
142
+ </ogc:Filter>
143
+ <PolygonSymbolizer>
144
+ <Fill>
145
+ <CssParameter name="fill-opacity">0.4</CssParameter>
146
+ <CssParameter name="fill">#aaaaaa</CssParameter>
147
+ </Fill>
148
+ <Stroke>
149
+ <CssParameter name="stroke-width">2</CssParameter>
150
+ <CssParameter name="stroke">#dddddd</CssParameter>
151
+ </Stroke>
152
+ </PolygonSymbolizer>
153
+ </Rule>
154
+ </FeatureTypeStyle>
155
+ <!-- Polygon with combined simple and complex Filter -->
156
+ <FeatureTypeStyle>
157
+ <Rule>
158
+ <ogc:Filter>
159
+ <ogc:And>
160
+ <ogc:PropertyIsEqualTo>
161
+ <ogc:Function name="geometryType">
162
+ <ogc:PropertyName>the_geom</ogc:PropertyName>
163
+ </ogc:Function>
164
+ <ogc:Literal>Polygon</ogc:Literal>
165
+ </ogc:PropertyIsEqualTo>
166
+ <ogc:Or>
167
+ <ogc:PropertyIsNull>
168
+ <ogc:PropertyName>highway</ogc:PropertyName>
169
+ </ogc:PropertyIsNull>
170
+ <ogc:Not>
171
+ <ogc:PropertyIsNull>
172
+ <ogc:PropertyName>waterway</ogc:PropertyName>
173
+ </ogc:PropertyIsNull>
174
+ </ogc:Not>
175
+ <ogc:PropertyIsEqualTo>
176
+ <ogc:PropertyName>natural</ogc:PropertyName>
177
+ <ogc:Literal>water</ogc:Literal>
178
+ </ogc:PropertyIsEqualTo>
179
+ </ogc:Or>
180
+ </ogc:And>
181
+ </ogc:Filter>
182
+ <PolygonSymbolizer>
183
+ <Fill>
184
+ <CssParameter name="fill-opacity">0.4</CssParameter>
185
+ <CssParameter name="fill">#aaaaaa</CssParameter>
186
+ </Fill>
187
+ <Stroke>
188
+ <CssParameter name="stroke-width">2</CssParameter>
189
+ <CssParameter name="stroke">#dddddd</CssParameter>
190
+ </Stroke>
191
+ </PolygonSymbolizer>
192
+ </Rule>
193
+ </FeatureTypeStyle>
194
+ <!-- Multiple symbolizers and complex filter -->
195
+ <FeatureTypeStyle>
196
+ <Rule>
197
+ <ogc:Filter>
198
+ <ogc:And>
199
+ <ogc:Not>
200
+ <ogc:PropertyIsNull>
201
+ <ogc:PropertyName>highway</ogc:PropertyName>
202
+ </ogc:PropertyIsNull>
203
+ </ogc:Not>
204
+ <ogc:Or>
205
+ <ogc:PropertyIsEqualTo>
206
+ <ogc:PropertyName>highway</ogc:PropertyName>
207
+ <ogc:Literal>secondary</ogc:Literal>
208
+ </ogc:PropertyIsEqualTo>
209
+ <ogc:PropertyIsEqualTo>
210
+ <ogc:PropertyName>highway</ogc:PropertyName>
211
+ <ogc:Literal>tertiary</ogc:Literal>
212
+ </ogc:PropertyIsEqualTo>
213
+ </ogc:Or>
214
+ </ogc:And>
215
+ </ogc:Filter>
216
+ <LineSymbolizer>
217
+ <Stroke>
218
+ <CssParameter name="stroke-width">7</CssParameter>
219
+ <CssParameter name="stroke">#303030</CssParameter>
220
+ </Stroke>
221
+ </LineSymbolizer>
222
+ <LineSymbolizer>
223
+ <Stroke>
224
+ <CssParameter name="stroke-width">5</CssParameter>
225
+ <CssParameter name="stroke">#e0e0ff</CssParameter>
226
+ </Stroke>
227
+ </LineSymbolizer>
228
+ </Rule>
229
+ </FeatureTypeStyle>
230
+ </UserStyle>
231
+ </NamedLayer>
232
+ </StyledLayerDescriptor>
@@ -0,0 +1 @@
1
+ require 'amanzi/sld'
@@ -0,0 +1,222 @@
1
+ #/usr/bin/env ruby
2
+
3
+ # The Amanzi:SLD module contains classes for a DSL for specifying
4
+ # StyleLayerDescriptor XML documents in a much simpler syntax than
5
+ # the usual XML syntax. It is based on the Amanzi::XML DSL which
6
+ # by itself already makes the syntax much simpler. You can access
7
+ # the underlying Amanzi::XML syntax as well, should you wish, but
8
+ # The SLD syntax makes common things much easier.
9
+ #
10
+ # For example, specify a PolygonSymbolizer like this:
11
+ # require 'amanzi/sld'
12
+ # sld = Amanzi::SLD::Document.new "Example"
13
+ # sld.add_polygon_symbolizer :stroke_width => 2, :stroke => '#dddddd', :fill => '#aaaaaa', :fill_opacity => 0.4
14
+
15
+ require 'amanzi/xml'
16
+
17
+ module Amanzi
18
+ module SLD
19
+ class Config
20
+ attr_accessor :settings
21
+ def self.config(options={})
22
+ @@instance ||= Config.new(options)
23
+ end
24
+ def initialize(options={})
25
+ @settings = options
26
+ end
27
+ def []=(key,value)
28
+ settings[key] = value
29
+ end
30
+ def [](key)
31
+ settings[key]
32
+ end
33
+ end
34
+ module Logger
35
+ def puts *args
36
+ STDOUT.puts(*args) if(Config.config[:verbose])
37
+ end
38
+ end
39
+ class Document < XML::Document
40
+ include Logger
41
+ attr_reader :sld_name, :style_name, :name, :geometry_property
42
+ def initialize(name,options={})
43
+ super 'StyledLayerDescriptor'
44
+ self['version'] = '1.0.0'
45
+ self['xmlns'] = "http://www.opengis.net/sld"
46
+ self['xmlns:ogc'] ="http://www.opengis.net/ogc"
47
+ self['xmlns:xlink'] = "http://www.w3.org/1999/xlink"
48
+ self['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
49
+ self['xsi:schemaLocation'] = "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
50
+ add_singleton_elements ['named_layer','user_style']
51
+ singleton_method(:named_layer).insert_child(0,'Name') << name
52
+ singleton_method(:user_style).insert_child(0,'Name') << name
53
+ end
54
+ # Pass any unknown methods down to user_style
55
+ def method_missing(symbol,*args,&block)
56
+ puts "Looking for SLD document method: #{symbol}"
57
+ singleton_method(symbol,*args,&block) ||
58
+ singleton_method(:user_style).send(symbol, *args, &block)
59
+ end
60
+ def add_line_symbolizer(options={},*args,&block)
61
+ RuleBuilder.new(self.feature_type_style.rule).add_line_symbolizer(options,*args,&block)
62
+ end
63
+ def add_polygon_symbolizer(options={},*args,&block)
64
+ RuleBuilder.new(self.feature_type_style.rule).add_polygon_symbolizer(options,*args,&block)
65
+ end
66
+ def add_text_symbolizer(options={},*args,&block)
67
+ RuleBuilder.new(self.feature_type_style.rule).add_text_symbolizer(options,*args,&block)
68
+ end
69
+ def add_rule(options={})
70
+ puts "Adding a generic rule: #{options.inspect}"
71
+ self.feature_type_style do |fs|
72
+ rule_builder = RuleBuilder.new(rule)
73
+ yield rule_builder if(block_given?)
74
+ rule_builder
75
+ end
76
+ end
77
+ end
78
+ class ElementWrapper
79
+ include Logger
80
+ attr_reader :element
81
+ def initialize(element)
82
+ @element = element
83
+ end
84
+ def method_missing(symbol,*args,&block)
85
+ puts "Method '#{symbol}' missing on Element Wrapper: #{self.inspect}"
86
+ element.send(symbol,*args,&block)
87
+ end
88
+ end
89
+ class RuleBuilder < ElementWrapper
90
+ alias_method :rule, :element
91
+ def initialize(rule)
92
+ super rule
93
+ end
94
+ def style_it(it,prefix,options={})
95
+ options.each do |k,v|
96
+ if k.to_s =~ /^#{prefix}/
97
+ it.css_parameter(:name => k.to_s.gsub(/_/,'-')) << v
98
+ end
99
+ end
100
+ end
101
+ def style_stroke(stroke,options={})
102
+ style_it(stroke,:stroke,options)
103
+ end
104
+ def style_fill(fill,options={})
105
+ style_it(fill,:fill,options)
106
+ end
107
+ def style_font(font,options={})
108
+ style_it(font,:font,options)
109
+ end
110
+ def update_filter_block(options,&block)
111
+ new_block = block
112
+ self.max_scale_denominator << options[:max_scale].to_f if(options[:max_scale])
113
+ self.min_scale_denominator << options[:min_scale].to_f if(options[:min_scale])
114
+ if(options[:geometry])
115
+ if(block)
116
+ new_block = Proc.new do |f|
117
+ f.op(:and) do |f|
118
+ f.geometry = options[:geometry]
119
+ block.call f
120
+ end
121
+ end
122
+ else
123
+ new_block = Proc.new {|f| f.geometry = options[:geometry]}
124
+ end
125
+ end
126
+ new_block
127
+ end
128
+ def add_line_symbolizer(options={},*args,&block)
129
+ options[:stroke] ||= '#000000'
130
+ options[:stroke_width] ||= 1
131
+ puts "RuleBuilder:Adding line symbolizer with options: #{options.inspect}"
132
+ block = update_filter_block(options,&block)
133
+ block.call FilterBuilder.new(rule.insert_child(0,'Filter').ns(:ogc)) if(block)
134
+ style_stroke(rule.line_symbolizer.stroke,options)
135
+ self
136
+ end
137
+ def add_polygon_symbolizer(options={},*args,&block)
138
+ options[:fill] ||= '#b0b0b0'
139
+ puts "Adding polygon symbolizer with options: #{options.inspect}"
140
+ block = update_filter_block(options,&block)
141
+ block.call FilterBuilder.new(rule.insert_child(0,'Filter').ns(:ogc)) if(block)
142
+ rule.polygon_symbolizer do |p|
143
+ style_fill(p.fill,options)
144
+ style_stroke(p.stroke,options)
145
+ end
146
+ self
147
+ end
148
+ def add_text_symbolizer(options={},*args,&block)
149
+ return self unless options[:text] || options[:property]
150
+ options[:font_family] ||= 'Times New Roman'
151
+ options[:font_style] ||= 'Normal'
152
+ options[:font_size] ||= 14
153
+ options[:font_weight] ||= 'bold'
154
+ options[:font_color] ||= '#101010'
155
+ options[:fill] ||= '#101010'
156
+ options[:halo_style] ||= {:fill => '#ffffbb', :fill_opacity => 0.85}
157
+ puts "Adding text symbolizer with options: #{options.inspect}"
158
+ block = update_filter_block(options,&block)
159
+ block.call FilterBuilder.new(rule.insert_child(0,'Filter').ns(:ogc)) if(block)
160
+ rule.text_symbolizer do |p|
161
+ if options[:property]
162
+ p.label.ogc__property_name << options[:property]
163
+ else
164
+ p.label.ogc__literal << options[:text]
165
+ end
166
+ style_font(p.font,options)
167
+ if options[:halo].to_i > 0
168
+ p.halo do |h|
169
+ h.radius.ogc__literal << options[:halo].to_i
170
+ style_fill(h.fill,options[:halo_style])
171
+ end
172
+ end
173
+ style_fill(p.fill,options)
174
+ end
175
+ self
176
+ end
177
+ end
178
+ class FilterBuilder < ElementWrapper
179
+ def initialize(filter)
180
+ super filter
181
+ puts "Created filter builder: #{element}"
182
+ end
183
+ def geometry=(type)
184
+ element.property_is_equal_to do |f|
185
+ f.function(:name => 'geometryType').property_name << (Config.config[:geometry_property] || 'geom')
186
+ f.literal << type
187
+ end
188
+ end
189
+ def property
190
+ @property ||= PropertyFilterBuilder.new(element)
191
+ end
192
+ def op(op_type)
193
+ op_type = op_type.to_s.intern
194
+ @op ||= {}
195
+ yield(@op[op_type] ||= BooleanFilterBuilder.new(element,op_type)) if(block_given?)
196
+ @op[op_type]
197
+ end
198
+ end
199
+ class PropertyFilterBuilder < ElementWrapper
200
+ def initialize(filter)
201
+ super filter
202
+ end
203
+ def []=(key,value)
204
+ element.property_is_equal_to do |f|
205
+ f.property_name << key.to_s
206
+ f.literal << value.to_s
207
+ end
208
+ end
209
+ def exists? name
210
+ element.send(:not).property_is_null.property_name << name
211
+ end
212
+ def not_exists? name
213
+ element.property_is_null.property_name << name
214
+ end
215
+ end
216
+ class BooleanFilterBuilder < FilterBuilder
217
+ def initialize(filter,op)
218
+ super(filter.send(op))
219
+ end
220
+ end
221
+ end
222
+ end