clevic 0.13.0.b9 → 0.13.0.b10
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.
- data/History.txt +3 -0
- data/lib/clevic/action_builder.rb +16 -16
- data/lib/clevic/ar_methods.rb +22 -22
- data/lib/clevic/attribute_list.rb +5 -5
- data/lib/clevic/cache_table.rb +18 -18
- data/lib/clevic/dataset_roller.rb +3 -3
- data/lib/clevic/default_view.rb +4 -4
- data/lib/clevic/delegate.rb +8 -8
- data/lib/clevic/delegates/combo_delegate.rb +22 -22
- data/lib/clevic/delegates/distinct_delegate.rb +5 -5
- data/lib/clevic/delegates/relational_delegate.rb +6 -6
- data/lib/clevic/delegates/set_delegate.rb +3 -3
- data/lib/clevic/dirty.rb +1 -1
- data/lib/clevic/emitter.rb +3 -3
- data/lib/clevic/extensions.rb +4 -4
- data/lib/clevic/field.rb +68 -68
- data/lib/clevic/field_valuer.rb +26 -26
- data/lib/clevic/filter_command.rb +6 -6
- data/lib/clevic/framework.rb +3 -3
- data/lib/clevic/generic_format.rb +2 -2
- data/lib/clevic/many_field.rb +3 -3
- data/lib/clevic/model_builder.rb +88 -84
- data/lib/clevic/model_column.rb +13 -13
- data/lib/clevic/ordered_dataset.rb +7 -7
- data/lib/clevic/qt/action_builder.rb +3 -3
- data/lib/clevic/qt/browser.rb +28 -28
- data/lib/clevic/qt/clipboard.rb +5 -5
- data/lib/clevic/qt/combo_delegate.rb +12 -12
- data/lib/clevic/qt/distinct_delegate.rb +1 -1
- data/lib/clevic/qt/extensions.rb +4 -4
- data/lib/clevic/qt/qt_combo_box.rb +7 -7
- data/lib/clevic/qt/relational_delegate.rb +5 -5
- data/lib/clevic/qt/search_dialog.rb +15 -15
- data/lib/clevic/qt/simplest_delegate.rb +2 -2
- data/lib/clevic/qt/table_model.rb +46 -46
- data/lib/clevic/qt/table_view.rb +48 -48
- data/lib/clevic/qt/text_delegate.rb +9 -9
- data/lib/clevic/rails_models_loaders.rb +3 -3
- data/lib/clevic/record.rb +8 -8
- data/lib/clevic/sampler.rb +6 -6
- data/lib/clevic/sequel_ar_adapter.rb +22 -22
- data/lib/clevic/sequel_clevic.rb +10 -10
- data/lib/clevic/sequel_meta.rb +5 -5
- data/lib/clevic/sequel_naked.rb +4 -4
- data/lib/clevic/swing/action.rb +20 -20
- data/lib/clevic/swing/action_builder.rb +2 -2
- data/lib/clevic/swing/boolean_delegate.rb +3 -3
- data/lib/clevic/swing/browser.rb +37 -37
- data/lib/clevic/swing/cell_editor.rb +13 -13
- data/lib/clevic/swing/cell_renderer.rb +7 -7
- data/lib/clevic/swing/clipboard.rb +19 -19
- data/lib/clevic/swing/combo_delegate.rb +26 -26
- data/lib/clevic/swing/confirm_dialog.rb +7 -7
- data/lib/clevic/swing/delegate.rb +4 -4
- data/lib/clevic/swing/extensions.rb +24 -24
- data/lib/clevic/swing/field.rb +1 -1
- data/lib/clevic/swing/relational_delegate.rb +2 -2
- data/lib/clevic/swing/row_header.rb +32 -32
- data/lib/clevic/swing/search_dialog.rb +31 -31
- data/lib/clevic/swing/selection_model.rb +12 -12
- data/lib/clevic/swing/swing_table_index.rb +6 -6
- data/lib/clevic/swing/table_model.rb +30 -30
- data/lib/clevic/swing/table_view.rb +54 -54
- data/lib/clevic/swing/table_view_focus.rb +4 -4
- data/lib/clevic/swing/tag_delegate.rb +14 -14
- data/lib/clevic/swing/tag_editor.rb +4 -4
- data/lib/clevic/swing/text_area_delegate.rb +6 -6
- data/lib/clevic/swing/text_delegate.rb +4 -4
- data/lib/clevic/table_index.rb +14 -14
- data/lib/clevic/table_model.rb +30 -30
- data/lib/clevic/table_searcher.rb +19 -19
- data/lib/clevic/table_view.rb +92 -92
- data/lib/clevic/table_view_paste.rb +19 -19
- data/lib/clevic/version.rb +1 -1
- data/lib/clevic/view.rb +22 -22
- data/models/accounts_models.rb +10 -10
- data/models/examples.rb +2 -2
- data/models/times_models.rb +32 -32
- data/models/values_models.rb +2 -2
- data/test/test_cache_table.rb +15 -15
- data/test/test_helper.rb +7 -7
- data/test/test_model_index_extensions.rb +6 -6
- data/test/test_table_model.rb +6 -6
- data/test/test_table_searcher.rb +25 -25
- metadata +33 -35
@@ -8,14 +8,14 @@ class TagEditor < javax.swing.JComponent
|
|
8
8
|
def initialize( field )
|
9
9
|
super()
|
10
10
|
@field = field
|
11
|
-
|
11
|
+
|
12
12
|
create_fields
|
13
13
|
init_layout
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
attr_reader :field
|
17
17
|
attr_reader :entity
|
18
|
-
|
18
|
+
|
19
19
|
# Hopefully called by the editor framework
|
20
20
|
# might be init_component
|
21
21
|
def configureEditor( editor, entity )
|
@@ -34,7 +34,7 @@ class TagEditor < javax.swing.JComponent
|
|
34
34
|
@add_button = javax.swing.JButton.new
|
35
35
|
@remove_button = javax.swing.JButton.new
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def init_layout
|
39
39
|
# This is mostly cut-n-pasted from the Netbeans Java sources. So don't tweak it.
|
40
40
|
text_field.setName("text_field");
|
@@ -12,7 +12,7 @@ module Clevic
|
|
12
12
|
super( newrect )
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
class TextAreaDelegate < Delegate
|
17
17
|
# TODO check that Ctrl-VK_ENTER stops editing
|
18
18
|
def init_component( cell_editor )
|
@@ -21,23 +21,23 @@ module Clevic
|
|
21
21
|
text_component.rows = ( edit_value.andand.count( "\n" ) || 0 ) + 2
|
22
22
|
text_component.select_all
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def editor
|
26
26
|
@editor ||= EditorScrollPane.new( text_component, javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS )
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def text_component
|
30
30
|
@text_component ||= javax.swing.JTextArea.new
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def value
|
34
34
|
text_component.text
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def minimal_edit
|
38
38
|
text_component.select_all
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def needs_pre_selection?
|
42
42
|
true
|
43
43
|
end
|
@@ -8,21 +8,21 @@ module Clevic
|
|
8
8
|
editor.text = edit_value
|
9
9
|
editor.select_all
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def editor
|
13
13
|
@editor ||= javax.swing.JTextField.new.tap do |e|
|
14
14
|
e.horizontal_alignment = field.swing_alignment
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def value
|
19
19
|
editor.text
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def minimal_edit
|
23
23
|
editor.select_all
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def needs_pre_selection?
|
27
27
|
true
|
28
28
|
end
|
data/lib/clevic/table_index.rb
CHANGED
@@ -4,12 +4,12 @@ module Clevic
|
|
4
4
|
# to be included in something that responds to model, row, column
|
5
5
|
module TableIndex
|
6
6
|
include FieldValuer
|
7
|
-
|
7
|
+
|
8
8
|
# return the Clevic::Field for this index
|
9
9
|
def field
|
10
10
|
@field ||= model.field_for_index( self )
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def dump
|
14
14
|
if valid?
|
15
15
|
<<-EOF
|
@@ -21,35 +21,35 @@ module Clevic
|
|
21
21
|
'invalid'
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def prev
|
26
26
|
choppy( :row => row - 1 )
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# return the attribute of the underlying entity corresponding
|
30
30
|
# to the column of this index
|
31
31
|
def attribute
|
32
32
|
model.attributes[column]
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
# returns the list of ModelColumn metadata
|
36
36
|
def meta
|
37
37
|
# use the optimised version
|
38
38
|
# TODO just use the model version instead?
|
39
39
|
field.meta
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# return the table's field name. For associations, this would
|
43
43
|
# be suffixed with _id
|
44
44
|
def field_name
|
45
45
|
meta.name
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# return the value of the field, it may be the _id value
|
49
49
|
def field_value
|
50
50
|
entity.send( field_name )
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
# the underlying entity
|
54
54
|
# TODO caching doesn't help with Qt because ModelIndex objects are
|
55
55
|
# extremely short-lived. Not sure about swing.
|
@@ -57,9 +57,9 @@ module Clevic
|
|
57
57
|
return nil if model.nil?
|
58
58
|
model.collection[row]
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
attr_writer :entity
|
62
|
-
|
62
|
+
|
63
63
|
# return true if validation failed for this indexes field
|
64
64
|
def has_errors?
|
65
65
|
# virtual fields don't have metadata
|
@@ -69,14 +69,14 @@ module Clevic
|
|
69
69
|
entity.errors.invalid?( field_name.to_sym )
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
# return a collection of errors. Unlike AR, this
|
74
74
|
# will always return an array that will have zero, one
|
75
75
|
# or many elements.
|
76
76
|
def errors
|
77
77
|
[ entity.errors[field_name.to_sym] ].flatten
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
# sort by row, then column
|
81
81
|
def <=>( other )
|
82
82
|
row_comp = self.row <=> other.row
|
@@ -86,11 +86,11 @@ module Clevic
|
|
86
86
|
row_comp
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
def inspect
|
91
91
|
"#<TableIndex (#{row},#{column}) '#{raw_value rescue "no raw value: #{$!.message}"}'>"
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# return a string (row,column)
|
95
95
|
# suitable for displaying to users, ie 1-based not 0-based
|
96
96
|
def rc
|
data/lib/clevic/table_model.rb
CHANGED
@@ -15,10 +15,10 @@ class TableModel
|
|
15
15
|
# the CacheTable of Clevic::Record or Sequel::Model objects
|
16
16
|
attr_reader :collection
|
17
17
|
alias_method :cache_table, :collection
|
18
|
-
|
18
|
+
|
19
19
|
# the collection of Clevic::Field objects
|
20
20
|
attr_reader :fields
|
21
|
-
|
21
|
+
|
22
22
|
attr_accessor :read_only
|
23
23
|
def read_only?; read_only; end
|
24
24
|
|
@@ -26,69 +26,69 @@ class TableModel
|
|
26
26
|
attr_accessor :auto_new
|
27
27
|
def auto_new?; auto_new; end
|
28
28
|
def auto_new?; auto_new; end
|
29
|
-
|
29
|
+
|
30
30
|
attr_accessor :entity_view
|
31
31
|
attr_accessor :builder
|
32
|
-
|
32
|
+
|
33
33
|
# If somre or all the entities in the collection is related to a single entity
|
34
34
|
# somewhere else, this is it. Not sure if this is the right
|
35
35
|
# way to do it, but try anyway.
|
36
36
|
attr_accessor :one
|
37
|
-
|
37
|
+
|
38
38
|
def entity_class
|
39
39
|
entity_view.entity_class
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def fields=( arr )
|
43
43
|
@fields = arr
|
44
|
-
|
44
|
+
|
45
45
|
# reset these
|
46
46
|
@labels = nil
|
47
47
|
@attributes = nil
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# field is a symbol or string referring to a column.
|
51
51
|
# returns the index of that field.
|
52
52
|
def field_column( field )
|
53
53
|
fields.each_with_index {|x,i| return i if x.id == field.to_sym }
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def field_for_index( model_index )
|
57
57
|
fields[model_index.column]
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def labels
|
61
61
|
@labels ||= fields.map {|x| x.label }
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def attributes
|
65
65
|
@attributes ||= fields.map {|x| x.attribute }
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def collection=( arr )
|
69
69
|
@collection = arr
|
70
70
|
# fill in an empty record for data entry
|
71
71
|
add_new_item if collection.empty? && auto_new?
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
# add a new item, and set defaults from the Clevic::View
|
75
75
|
# add_new_item_start and add_new_item_end are provided by
|
76
76
|
# the GUI framework-specific class
|
77
77
|
def add_new_item
|
78
78
|
add_new_item_start
|
79
|
-
|
79
|
+
|
80
80
|
entity = entity_class.new
|
81
|
-
|
81
|
+
|
82
82
|
# set default values without triggering changed
|
83
83
|
fields.each do |f|
|
84
84
|
f.set_default_for( entity ) unless f.default.nil?
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
collection << entity
|
88
|
-
|
88
|
+
|
89
89
|
add_new_item_end
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
# rows is a collection of integers specifying row indices to remove
|
93
93
|
def remove_rows( rows )
|
94
94
|
# don't delete rows twice
|
@@ -99,25 +99,25 @@ class TableModel
|
|
99
99
|
removals = rows_in_order.map do |index|
|
100
100
|
collection[index]
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
remove_notify( rows_in_order ) do
|
104
104
|
removals.each do |to_remove, index|
|
105
105
|
# destroy the db object, and its associated table row
|
106
106
|
to_remove.destroy unless to_remove.nil? || to_remove.new?
|
107
107
|
end
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
# because it's too bloody complicated to figure out which items
|
111
111
|
# were deleted and then remove them from the collection. And there
|
112
112
|
# most likely isn't a big hit for doing this, unless there's a lot
|
113
113
|
# of cached calcuation in the entities.
|
114
114
|
self.collection = collection.renew
|
115
|
-
|
115
|
+
|
116
116
|
# create a new row if auto_new is on
|
117
117
|
# should really be in a signal handler
|
118
118
|
add_new_item if collection.empty? && auto_new?
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
# save the model at the given index, if it's dirty
|
122
122
|
# TODO Sequel uses modified?
|
123
123
|
def save( index )
|
@@ -141,7 +141,7 @@ class TableModel
|
|
141
141
|
puts $!.backtrace
|
142
142
|
emit_data_error( index, nil, $!.message )
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
def reload_data( dataset = nil, &dataset_block )
|
146
146
|
# renew cache. All records will be dropped and reloaded.
|
147
147
|
self.collection = self.cache_table.renew( dataset, &dataset_block )
|
@@ -159,7 +159,7 @@ class TableModel
|
|
159
159
|
start_index.field
|
160
160
|
)
|
161
161
|
entity = searcher.search( start_index.entity )
|
162
|
-
|
162
|
+
|
163
163
|
# return matched indexes
|
164
164
|
unless entity.nil?
|
165
165
|
found_row = collection.index_for_entity( entity )
|
@@ -169,12 +169,12 @@ class TableModel
|
|
169
169
|
[]
|
170
170
|
end
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
class DataChange
|
174
174
|
class ModelIndexProxy
|
175
175
|
attr_accessor :row
|
176
176
|
attr_accessor :column
|
177
|
-
|
177
|
+
|
178
178
|
def initialize( other = nil )
|
179
179
|
unless other.nil?
|
180
180
|
@row = other.row
|
@@ -182,18 +182,18 @@ class TableModel
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
end
|
185
|
-
|
185
|
+
|
186
186
|
def top_left
|
187
187
|
@top_left ||= ModelIndexProxy.new
|
188
188
|
end
|
189
|
-
|
189
|
+
|
190
190
|
def bottom_right
|
191
191
|
@bottom_right ||= ModelIndexProxy.new
|
192
192
|
end
|
193
|
-
|
193
|
+
|
194
194
|
attr_writer :bottom_right
|
195
195
|
attr_writer :top_left
|
196
|
-
|
196
|
+
|
197
197
|
attr_reader :index
|
198
198
|
def index=( other )
|
199
199
|
self.top_left = ModelIndexProxy.new( other )
|
@@ -11,20 +11,20 @@ the matching record next after this.
|
|
11
11
|
class TableSearcher
|
12
12
|
include OrderedDataset
|
13
13
|
attr_reader :search_criteria, :field
|
14
|
-
|
14
|
+
|
15
15
|
# dataset is a Sequel::Dataset, which has an associated Sequel::Model
|
16
16
|
# field is an instance of Clevic::Field
|
17
17
|
# search_criteria responds to from_start?, direction, whole_words? and search_text
|
18
18
|
def initialize( dataset, search_criteria, field )
|
19
19
|
raise "field must be specified" if field.nil?
|
20
20
|
raise "unknown order #{search_criteria.direction}" unless [:forwards, :backwards].include?( search_criteria.direction )
|
21
|
-
|
21
|
+
|
22
22
|
self.dataset = dataset
|
23
|
-
|
23
|
+
|
24
24
|
@search_criteria = search_criteria
|
25
25
|
@field = field
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# start_entity is the entity to start from, ie any record found after it will qualify
|
29
29
|
# return the first entity found that matches the criteria
|
30
30
|
def search( start_entity = nil )
|
@@ -36,12 +36,12 @@ protected
|
|
36
36
|
def search_field_expression
|
37
37
|
if field.association?
|
38
38
|
raise "display not specified for #{field}" if field.display.nil?
|
39
|
-
|
39
|
+
|
40
40
|
# for related table displays as procs
|
41
41
|
unless [String,Symbol].include?( field.display.class )
|
42
42
|
raise( "search field #{field.inspect} cannot search lambda display" )
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
# TODO this will only work with a path value with no dots
|
46
46
|
# otherwise the SQL gets complicated with joins etc
|
47
47
|
field.related_class \
|
@@ -52,7 +52,7 @@ protected
|
|
52
52
|
field.attribute.to_sym
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
# return an expression, or an array or expressions for representing search_criteria.search_text and whole_words?
|
57
57
|
def search_text_expression
|
58
58
|
if search_criteria.whole_words?
|
@@ -66,7 +66,7 @@ protected
|
|
66
66
|
"%#{search_criteria.search_text}%"
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Add the relevant conditions to use start_entity as the
|
71
71
|
# entity where the search starts, ie the first one after it is found
|
72
72
|
# start_entity is a model instance
|
@@ -76,12 +76,12 @@ protected
|
|
76
76
|
# pure boolean expression - they need something to compare it to.
|
77
77
|
dataset.filter( expression => true )
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
# return a dataset based on dataset which filters on search_criteria
|
81
81
|
def search_dataset( start_entity )
|
82
82
|
likes = Array[*search_text_expression].map{|ste| Sequel::SQL::StringExpression.like(search_field_expression, ste, {:case_insensitive=>true})}
|
83
83
|
rv = dataset.filter( Sequel::SQL::BooleanExpression.new(:OR, *likes ) )
|
84
|
-
|
84
|
+
|
85
85
|
# if we're not searching from the start, we need
|
86
86
|
# to find the next match. Which is complicated from an SQL point of view.
|
87
87
|
unless search_criteria.from_start?
|
@@ -89,25 +89,25 @@ protected
|
|
89
89
|
# build up the ordering conditions
|
90
90
|
rv = find_from( rv, start_entity )
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
# reverse order by direction if necessary
|
94
94
|
rv = rv.reverse if search_criteria.direction == :backwards
|
95
|
-
|
95
|
+
|
96
96
|
# return dataset
|
97
97
|
rv
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
# recursively create a case statement to do the comparison
|
101
101
|
# because and ... and ... and filters on *each* one rather than
|
102
102
|
# consecutively.
|
103
103
|
def build_recursive_comparison( start_entity, index = 0 )
|
104
104
|
# end recursion
|
105
105
|
return false if index == order_attributes.size
|
106
|
-
|
106
|
+
|
107
107
|
# fetch the current order attribute and direction
|
108
108
|
attribute, direction = order_attributes[index]
|
109
109
|
value = start_entity.send( attribute )
|
110
|
-
|
110
|
+
|
111
111
|
# build case statement using Sequel expressions, including recursion
|
112
112
|
# pseudo-SQL is
|
113
113
|
# case
|
@@ -115,7 +115,7 @@ protected
|
|
115
115
|
# when attribute = value then #{build_recursive_comparison( operator, index+1 )}
|
116
116
|
# else false
|
117
117
|
# end
|
118
|
-
|
118
|
+
|
119
119
|
{
|
120
120
|
# if values are unequal, comparison levels end here
|
121
121
|
attribute.identifier.send( comparator(direction), value ) => true,
|
@@ -123,7 +123,7 @@ protected
|
|
123
123
|
{ attribute => value } => build_recursive_comparison( start_entity, index+1 )
|
124
124
|
}.case( false ) # the else (default) clause, ie we don't want to see these records
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
# return either > or < depending on both search_criteria.direction
|
128
128
|
# and local_direction
|
129
129
|
def comparator( local_direction = 1 )
|
@@ -132,11 +132,11 @@ protected
|
|
132
132
|
when :forwards; 1
|
133
133
|
when :backwards; -1
|
134
134
|
end * local_direction
|
135
|
-
|
135
|
+
|
136
136
|
# 1 indexes >, -1 indexes <
|
137
137
|
['','>','<'][comparator_direction]
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
end
|
141
141
|
|
142
142
|
end
|