rtext 0.7.0 → 0.8.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +4 -0
- data/RText_Protocol +8 -0
- data/Rakefile +1 -1
- data/lib/rtext/context_builder.rb +4 -2
- data/lib/rtext/frontend/context.rb +64 -32
- data/lib/rtext/language.rb +33 -4
- data/lib/rtext/parser.rb +12 -4
- data/lib/rtext/serializer.rb +29 -6
- data/lib/rtext/tokenizer.rb +12 -2
- data/test/context_builder_test.rb +8 -0
- data/test/frontend/context_test.rb +205 -0
- data/test/instantiator_test.rb +122 -31
- data/test/integration/backend.out +12 -12
- data/test/integration/frontend.log +2699 -0
- data/test/integration/model/test_metamodel.ect +8 -2
- data/test/integration/test.rb +247 -19
- data/test/link_detector_test.rb +11 -0
- data/test/rtext_test.rb +1 -0
- data/test/serializer_test.rb +388 -0
- data/test/tokenizer_test.rb +16 -0
- metadata +11 -14
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dfdb25504469a30431bda0d53f6ed450809ca7ba
|
4
|
+
data.tar.gz: 93de80eedec085dfb25d6fb1d5f134236f692c57
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dfe6ce9af736e941413be2ec99c4ad301ded2192affc6334dcf80eb795b2b9a98370b1174c385f852f0ba0788e9d2cf6db1130955eda6e845eca4758f5580e8d
|
7
|
+
data.tar.gz: 80f81b162444e33c346f5edacd961828c2311c9d99f1f404a94a62cac40a9f2dd6403608e7555da8f60210918f102cc92d308861dcf06ce871cdc2b0b00be79b
|
data/CHANGELOG
CHANGED
data/RText_Protocol
CHANGED
@@ -493,3 +493,11 @@ context in the frontend simple and the amount of data transmitted to the backend
|
|
493
493
|
It's also a way to keep the parsing time of the context low in the backend and thus to minimize
|
494
494
|
the user noticable delay.
|
495
495
|
|
496
|
+
In case of line breaks, the frontend is responsible to join the lines before sending the
|
497
|
+
context information. For commands which use a column position, the position is the position
|
498
|
+
within the joined line. This means that, when sending a command, the frontend must convert
|
499
|
+
the column position in the broken line into the new position in the joined line.
|
500
|
+
When reading back column information in a response (e.g. link command) the frontend must
|
501
|
+
convert the column position in the joined line into a position in the respective broken
|
502
|
+
fragment of a line.
|
503
|
+
|
data/Rakefile
CHANGED
@@ -103,8 +103,10 @@ module ContextBuilder
|
|
103
103
|
problem = nil
|
104
104
|
line = context_lines.last
|
105
105
|
if line =~ /\{\s*$/
|
106
|
-
# remove curly brace from last line, required for correct counting of num_elements
|
107
|
-
line
|
106
|
+
# remove curly brace from last line, required for correct counting of num_elements;
|
107
|
+
# also make sure that there is whitespace at the end of line, otherwise a word
|
108
|
+
# might get removed as "just being completed"
|
109
|
+
line.sub!(/\{\s*$/," ")
|
108
110
|
problem = :after_curly
|
109
111
|
end
|
110
112
|
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module RText
|
2
2
|
module Frontend
|
3
3
|
|
4
|
-
|
4
|
+
class Context
|
5
5
|
|
6
|
-
# lines
|
7
|
-
|
6
|
+
# lines: all lines from the beginning up to and including the current line
|
7
|
+
# pos: position of the cursor in the last lines
|
8
|
+
# returns the extracted lines and the new position in the last line
|
9
|
+
def extract(lines, pos)
|
10
|
+
lines = filter_lines(lines)
|
11
|
+
lines, new_pos = join_lines(lines, pos)
|
8
12
|
non_ignored_lines = 0
|
9
13
|
array_nesting = 0
|
10
14
|
block_nesting = 0
|
@@ -14,39 +18,67 @@ def self.extract(lines)
|
|
14
18
|
if i == 0
|
15
19
|
result.unshift(l)
|
16
20
|
else
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
block_nesting -= 1
|
26
|
-
elsif block_nesting == 0
|
27
|
-
result.unshift(l)
|
28
|
-
last_element_line = non_ignored_lines
|
29
|
-
end
|
30
|
-
when "}"
|
31
|
-
block_nesting += 1
|
32
|
-
when "["
|
33
|
-
if array_nesting > 0
|
34
|
-
array_nesting -= 1
|
35
|
-
elsif array_nesting == 0
|
36
|
-
result.unshift(l)
|
37
|
-
end
|
38
|
-
when "]"
|
39
|
-
array_nesting += 1
|
40
|
-
when ":"
|
41
|
-
# lable directly above element
|
42
|
-
if non_ignored_lines == last_element_line + 1
|
43
|
-
result.unshift(l)
|
44
|
-
end
|
21
|
+
non_ignored_lines += 1
|
22
|
+
case l.strip[-1..-1]
|
23
|
+
when "{"
|
24
|
+
if block_nesting > 0
|
25
|
+
block_nesting -= 1
|
26
|
+
elsif block_nesting == 0
|
27
|
+
result.unshift(l)
|
28
|
+
last_element_line = non_ignored_lines
|
45
29
|
end
|
30
|
+
when "}"
|
31
|
+
block_nesting += 1
|
32
|
+
when "["
|
33
|
+
if array_nesting > 0
|
34
|
+
array_nesting -= 1
|
35
|
+
elsif array_nesting == 0
|
36
|
+
result.unshift(l)
|
37
|
+
end
|
38
|
+
when "]"
|
39
|
+
array_nesting += 1
|
40
|
+
when ":"
|
41
|
+
# lable directly above element
|
42
|
+
if non_ignored_lines == last_element_line + 1
|
43
|
+
result.unshift(l)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
[result, new_pos]
|
49
|
+
end
|
50
|
+
|
51
|
+
def filter_lines(lines)
|
52
|
+
lines.reject { |l|
|
53
|
+
ls = l.strip
|
54
|
+
ls[0..0] == "@" || ls[0..0] == "#"
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# when joining two lines, all whitespace after the last character of the first line is removed
|
59
|
+
# (after , and [); however whitespace at the end of the last of several joined lines is preserved;
|
60
|
+
# this way the context is correct even if the cursor is after the end of the last line
|
61
|
+
# (i.e. with whitespace after the last non-whitespace character)
|
62
|
+
def join_lines(lines, pos)
|
63
|
+
outlines = []
|
64
|
+
while lines.size > 0
|
65
|
+
outlines << lines.shift
|
66
|
+
while lines.size > 0 &&
|
67
|
+
(outlines.last =~ /,\s*$/ ||
|
68
|
+
(outlines.last =~ /\[\s*$/ && outlines.last =~ /,/) ||
|
69
|
+
(lines.first =~ /^\s*\]/ && outlines.last =~ /,/))
|
70
|
+
outlines.last.rstrip!
|
71
|
+
l = lines.shift
|
72
|
+
if lines.size == 0
|
73
|
+
# strip only left part, the prefix might have whitespace on the
|
74
|
+
# right hand side which is relevant for the position
|
75
|
+
non_ws_prefix = l[0..pos-1].lstrip
|
76
|
+
pos = outlines.last.size + non_ws_prefix.size
|
46
77
|
end
|
78
|
+
outlines.last.concat(l.lstrip)
|
47
79
|
end
|
48
80
|
end
|
49
|
-
|
81
|
+
[outlines, pos]
|
50
82
|
end
|
51
83
|
|
52
84
|
end
|
data/lib/rtext/language.rb
CHANGED
@@ -42,6 +42,16 @@ class Language
|
|
42
42
|
# (in sprintf syntax) which will be used by the serializer for integers and floats.
|
43
43
|
# default: if not present or the proc returns nil, then #to_s is used
|
44
44
|
#
|
45
|
+
# :newline_arguments
|
46
|
+
# a Proc which receives an EClass and should return the names of this EClass's features
|
47
|
+
# which are to be serialized after adding a line break.
|
48
|
+
# default: no attributes on new lines
|
49
|
+
#
|
50
|
+
# :newline_arrays
|
51
|
+
# a Proc which receives an EClass and should return the names of this EClass's features
|
52
|
+
# for which the array elements of their values are to be serialized after a line break.
|
53
|
+
# default: no attributes on new lines
|
54
|
+
#
|
45
55
|
# :reference_regexp
|
46
56
|
# a Regexp which is used by the tokenizer for identifying references
|
47
57
|
# it must only match at the beginning of a string, i.e. it should start with \A
|
@@ -53,20 +63,25 @@ class Language
|
|
53
63
|
# :identifier_provider
|
54
64
|
# a Proc which receives an element, its containing element, the feature through which the
|
55
65
|
# element is referenced and the index position of the reference within the feature's values.
|
56
|
-
# the latter 3
|
57
|
-
# the identifier must be unique for the element unless
|
66
|
+
# the latter 3 arguments may be nil. it should return the element's identifier as a string.
|
67
|
+
# the identifier must be unique for the element unless :per_type_identifier is set to true,
|
58
68
|
# in which case they must be unique for each element of the same type.
|
59
69
|
# identifiers may be relative to the given containing element, depending on the given
|
60
70
|
# feature and index position. in this case a globally unique
|
61
|
-
# identifier must be
|
71
|
+
# identifier must be reconstructed by the proc specified using the :reference_qualifier option.
|
62
72
|
# if the containing element is nil, the identifier returned must be globally unique.
|
63
|
-
# default: identifiers calculated by QualifiedNameProvider
|
73
|
+
# default: identifiers calculated by QualifiedNameProvider using the attribute provided using
|
74
|
+
# the :attribute_name option
|
64
75
|
# in this case options to QualifiedNameProvider may be provided and will be passed through
|
65
76
|
#
|
66
77
|
# :per_type_identifier
|
67
78
|
# if set to true, identifiers may be reused for elements of different type
|
68
79
|
# default: false
|
69
80
|
#
|
81
|
+
# :attribute_name
|
82
|
+
# the name of the attribute used to calculate identifiers by the default identifier provider
|
83
|
+
# default: "name"
|
84
|
+
#
|
70
85
|
# :reference_qualifier
|
71
86
|
# a Proc which receives RGen unresolved references and either a FragmentedModel or a ModelFragment.
|
72
87
|
# it should modify the unresolved references' targetIdentifiers to make them globally unique.
|
@@ -142,6 +157,8 @@ class Language
|
|
142
157
|
@unquoted_arguments = options[:unquoted_arguments]
|
143
158
|
@labeled_containments = options[:labeled_containments]
|
144
159
|
@argument_format_provider = options[:argument_format_provider]
|
160
|
+
@newline_arguments = options[:newline_arguments]
|
161
|
+
@newline_arrays = options[:newline_arrays]
|
145
162
|
@root_classes = options[:root_classes] || default_root_classes(root_epackage)
|
146
163
|
command_name_provider = options[:command_name_provider] || proc{|c| c.name}
|
147
164
|
setup_commands(root_epackage, command_name_provider)
|
@@ -232,6 +249,16 @@ class Language
|
|
232
249
|
@argument_format_provider && @argument_format_provider.call(feature)
|
233
250
|
end
|
234
251
|
|
252
|
+
def newline_argument?(clazz, feature)
|
253
|
+
return false unless @newline_arguments
|
254
|
+
@newline_arguments.call(clazz).include?(feature.name)
|
255
|
+
end
|
256
|
+
|
257
|
+
def newline_array?(clazz, feature)
|
258
|
+
return false unless @newline_arrays
|
259
|
+
@newline_arrays.call(clazz).include?(feature.name)
|
260
|
+
end
|
261
|
+
|
235
262
|
def concrete_types(clazz)
|
236
263
|
([clazz] + clazz.eAllSubTypes).select{|c| !c.abstract}
|
237
264
|
end
|
@@ -312,6 +339,8 @@ class Language
|
|
312
339
|
:labled_arguments,
|
313
340
|
:unquoted?,
|
314
341
|
:labeled_containment?,
|
342
|
+
:newline_argument?,
|
343
|
+
:newline_array?,
|
315
344
|
:argument_format,
|
316
345
|
:concrete_types,
|
317
346
|
:containments_by_target_type,
|
data/lib/rtext/parser.rb
CHANGED
@@ -130,7 +130,10 @@ class Parser
|
|
130
130
|
def parse_argument_list(arg_list)
|
131
131
|
first = true
|
132
132
|
while (AnyValue + [",", "[", :label, :error]).include?(next_token_kind)
|
133
|
-
|
133
|
+
unless first
|
134
|
+
success = consume(",")
|
135
|
+
consume(:newline) if success && next_token_kind == :newline
|
136
|
+
end
|
134
137
|
first = false
|
135
138
|
parse_argument(arg_list)
|
136
139
|
end
|
@@ -155,13 +158,18 @@ class Parser
|
|
155
158
|
|
156
159
|
def parse_argument_value_list
|
157
160
|
consume("[")
|
161
|
+
consume(:newline) if next_token_kind == :newline
|
158
162
|
first = true
|
159
163
|
result = []
|
160
164
|
while (AnyValue + [",", :error]).include?(next_token_kind)
|
161
|
-
|
165
|
+
unless first
|
166
|
+
success = consume(",")
|
167
|
+
consume(:newline) if success && next_token_kind == :newline
|
168
|
+
end
|
162
169
|
first = false
|
163
170
|
result << parse_value
|
164
171
|
end
|
172
|
+
consume(:newline) if next_token_kind == :newline && next_token_kind(1) == "]"
|
165
173
|
consume("]")
|
166
174
|
result
|
167
175
|
end
|
@@ -172,8 +180,8 @@ class Parser
|
|
172
180
|
consume(*AnyValue)
|
173
181
|
end
|
174
182
|
|
175
|
-
def next_token_kind
|
176
|
-
@tokens
|
183
|
+
def next_token_kind(idx=0)
|
184
|
+
@tokens[idx] && @tokens[idx].kind
|
177
185
|
end
|
178
186
|
|
179
187
|
def discard_until(kind)
|
data/lib/rtext/serializer.rb
CHANGED
@@ -72,13 +72,24 @@ class Serializer
|
|
72
72
|
args = []
|
73
73
|
@lang.unlabled_arguments(clazz).each do |f|
|
74
74
|
values = serialize_values(element, f)
|
75
|
-
args << values if values
|
75
|
+
args << [f, values] if values
|
76
76
|
end
|
77
77
|
@lang.labled_arguments(clazz).each do |f|
|
78
78
|
values = serialize_values(element, f)
|
79
|
-
args << "#{f.name}: #{values}" if values
|
79
|
+
args << [f, "#{f.name}: #{values}"] if values
|
80
|
+
end
|
81
|
+
newline_arguments = false
|
82
|
+
args.each_with_index do |arg, index|
|
83
|
+
if @lang.newline_argument?(clazz, arg[0])
|
84
|
+
headline += " \\" if index == 0
|
85
|
+
headline += "\n" + @lang.indent_string * (@indent + 1)
|
86
|
+
newline_arguments = true
|
87
|
+
else
|
88
|
+
headline += " "
|
89
|
+
end
|
90
|
+
headline += arg[1]
|
91
|
+
headline += "," unless index == args.size-1
|
80
92
|
end
|
81
|
-
headline += " "+args.join(", ") if args.size > 0
|
82
93
|
contained_elements = {}
|
83
94
|
@lang.containments(clazz).each do |f|
|
84
95
|
contained_elements[f] = element.getGenericAsArray(f.name)
|
@@ -87,6 +98,10 @@ class Serializer
|
|
87
98
|
headline += " {"
|
88
99
|
write(headline)
|
89
100
|
iinc
|
101
|
+
# additional indentation needed if there are arguments on separate lines;
|
102
|
+
# note that this increment doesn't affect indentation of features of this element
|
103
|
+
# that have array values, because they have already been formatted in serialize_values
|
104
|
+
iinc if newline_arguments
|
90
105
|
@lang.containments(clazz).each do |f|
|
91
106
|
childs = contained_elements[f]
|
92
107
|
if childs.size > 0
|
@@ -111,6 +126,7 @@ class Serializer
|
|
111
126
|
end
|
112
127
|
end
|
113
128
|
idec
|
129
|
+
idec if newline_arguments
|
114
130
|
write("}")
|
115
131
|
else
|
116
132
|
write(headline)
|
@@ -173,10 +189,17 @@ class Serializer
|
|
173
189
|
result << @lang.identifier_provider.call(v, element, feature, index)
|
174
190
|
end
|
175
191
|
end
|
176
|
-
if result.size > 1
|
177
|
-
|
192
|
+
if result.size > 1
|
193
|
+
if @lang.newline_array?(element.class.ecore, feature)
|
194
|
+
# inside an array, indent two steps further than the command
|
195
|
+
"[\n" + @lang.indent_string * (@indent + 2) +
|
196
|
+
result.join(",\n" + @lang.indent_string * (@indent + 2)) +
|
197
|
+
"\n" + @lang.indent_string * (@indent + 1) + "]"
|
198
|
+
else
|
199
|
+
"[#{result.join(", ")}]"
|
200
|
+
end
|
178
201
|
elsif result.size == 1
|
179
|
-
result.first
|
202
|
+
result.first
|
180
203
|
else
|
181
204
|
nil
|
182
205
|
end
|
data/lib/rtext/tokenizer.rb
CHANGED
@@ -10,6 +10,7 @@ module Tokenizer
|
|
10
10
|
def tokenize(str, reference_regexp, options={})
|
11
11
|
result = []
|
12
12
|
on_command_token_proc = options[:on_command_token]
|
13
|
+
linebreak = false
|
13
14
|
str.split(/\r?\n/).each_with_index do |str, idx|
|
14
15
|
idx += 1
|
15
16
|
if idx == 1
|
@@ -27,7 +28,12 @@ module Tokenizer
|
|
27
28
|
end
|
28
29
|
else
|
29
30
|
col = 1
|
30
|
-
|
31
|
+
if linebreak
|
32
|
+
# do not regard as the first token, if previous line ended in a linebreak
|
33
|
+
linebreak = false
|
34
|
+
else
|
35
|
+
first_token_in_line = true
|
36
|
+
end
|
31
37
|
until str.empty?
|
32
38
|
whitespace = false
|
33
39
|
case str
|
@@ -94,6 +100,10 @@ module Tokenizer
|
|
94
100
|
col += $&.size
|
95
101
|
whitespace = true
|
96
102
|
# ignore
|
103
|
+
when /\A\\\s*\Z/
|
104
|
+
str = $'
|
105
|
+
linebreak = true
|
106
|
+
# ignore
|
97
107
|
when /\A<%((?:(?!%>).)*)%>/, /\A<([^>]*)>/
|
98
108
|
str = $'
|
99
109
|
result << Token.new(:generic, RText::Generic.new($1), idx, col, col+$&.size-1)
|
@@ -107,7 +117,7 @@ module Tokenizer
|
|
107
117
|
end
|
108
118
|
end
|
109
119
|
result << Token.new(:newline, nil, idx) \
|
110
|
-
unless result.empty? || result.last.kind == :newline
|
120
|
+
unless linebreak || result.empty? || result.last.kind == :newline
|
111
121
|
end
|
112
122
|
result
|
113
123
|
end
|
@@ -397,6 +397,14 @@ TestNode {|
|
|
397
397
|
assert(c.element.is_a?(TestMM::TestNode))
|
398
398
|
end
|
399
399
|
|
400
|
+
def test_root_after_curly_no_ws
|
401
|
+
c = build_context TestMM, <<-END
|
402
|
+
TestNode{|
|
403
|
+
END
|
404
|
+
assert_context c, :prefix => "", :feature => nil, :in_array => false, :in_block => false, :problem => :after_curly
|
405
|
+
assert(c.element.is_a?(TestMM::TestNode))
|
406
|
+
end
|
407
|
+
|
400
408
|
def test_in_cmd_after_cmd
|
401
409
|
c = build_context TestMM, <<-END
|
402
410
|
TestNode text: a {
|
@@ -0,0 +1,205 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","..","lib")
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rtext/frontend/context'
|
5
|
+
|
6
|
+
class ContextTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_simple
|
9
|
+
assert_context(
|
10
|
+
%Q(
|
11
|
+
A {
|
12
|
+
B {
|
13
|
+
|F bla
|
14
|
+
),
|
15
|
+
%Q(
|
16
|
+
A {
|
17
|
+
B {
|
18
|
+
C a1: v1, a2: "v2"
|
19
|
+
D {
|
20
|
+
E a1: 5
|
21
|
+
}
|
22
|
+
|F bla
|
23
|
+
))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_child_label
|
27
|
+
assert_context(
|
28
|
+
%Q(
|
29
|
+
A {
|
30
|
+
sub:
|
31
|
+
B {
|
32
|
+
F bla|
|
33
|
+
),
|
34
|
+
%Q(
|
35
|
+
A {
|
36
|
+
sub:
|
37
|
+
B {
|
38
|
+
C a1: v1, a2: "v2"
|
39
|
+
D {
|
40
|
+
E a1: 5
|
41
|
+
}
|
42
|
+
F bla|
|
43
|
+
))
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_child_label_array
|
47
|
+
assert_context(
|
48
|
+
%Q(
|
49
|
+
A {
|
50
|
+
sub: [
|
51
|
+
B {
|
52
|
+
F| bla
|
53
|
+
),
|
54
|
+
%Q(
|
55
|
+
A {
|
56
|
+
sub: [
|
57
|
+
B {
|
58
|
+
C
|
59
|
+
}
|
60
|
+
B {
|
61
|
+
C a1: v1, a2: "v2"
|
62
|
+
D {
|
63
|
+
E a1: 5
|
64
|
+
}
|
65
|
+
F| bla
|
66
|
+
))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_ignore_child_lables
|
70
|
+
assert_context(
|
71
|
+
%Q(
|
72
|
+
A {
|
73
|
+
B {
|
74
|
+
F bl|a
|
75
|
+
),
|
76
|
+
%Q(
|
77
|
+
A {
|
78
|
+
B {
|
79
|
+
sub:
|
80
|
+
C a1: v1, a2: "v2"
|
81
|
+
sub2: [
|
82
|
+
D {
|
83
|
+
E a1: 5
|
84
|
+
}
|
85
|
+
]
|
86
|
+
F bl|a
|
87
|
+
))
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_linebreak
|
91
|
+
assert_context(
|
92
|
+
%Q(
|
93
|
+
A {
|
94
|
+
B {
|
95
|
+
C name,a1: v1,a2: "v2"|
|
96
|
+
),
|
97
|
+
%Q(
|
98
|
+
A {
|
99
|
+
B {
|
100
|
+
C name,
|
101
|
+
a1: v1,
|
102
|
+
a2: "v2"|
|
103
|
+
))
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_linebreak_arg_array
|
107
|
+
assert_context(
|
108
|
+
%Q(
|
109
|
+
A {
|
110
|
+
B {
|
111
|
+
C name,a1: [v1,v2],a2: |5
|
112
|
+
),
|
113
|
+
%Q(
|
114
|
+
A {
|
115
|
+
B {
|
116
|
+
C name,
|
117
|
+
a1: [
|
118
|
+
v1,
|
119
|
+
v2
|
120
|
+
],
|
121
|
+
a2: |5
|
122
|
+
))
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_linebreak_empty_last_line
|
126
|
+
assert_context(
|
127
|
+
%Q(
|
128
|
+
A {
|
129
|
+
B name,|
|
130
|
+
),
|
131
|
+
%Q(
|
132
|
+
A {
|
133
|
+
B name,
|
134
|
+
|
|
135
|
+
))
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_linebreak_empty_last_line2
|
139
|
+
assert_context(
|
140
|
+
%Q(
|
141
|
+
A {
|
142
|
+
B name,|
|
143
|
+
),
|
144
|
+
%Q(
|
145
|
+
A {
|
146
|
+
B name,
|
147
|
+
|
|
148
|
+
))
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_linebreak_empty_lines
|
152
|
+
assert_context(
|
153
|
+
%Q(
|
154
|
+
A {
|
155
|
+
B name,a1: |
|
156
|
+
),
|
157
|
+
%Q(
|
158
|
+
A {
|
159
|
+
B name,
|
160
|
+
|
161
|
+
a1: |
|
162
|
+
))
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_comment_annotation
|
166
|
+
assert_context(
|
167
|
+
%Q(
|
168
|
+
A {
|
169
|
+
B {
|
170
|
+
|F bla
|
171
|
+
),
|
172
|
+
%Q(
|
173
|
+
A {
|
174
|
+
# bla
|
175
|
+
B {
|
176
|
+
C a1: v1, a2: "v2"
|
177
|
+
# bla
|
178
|
+
D {
|
179
|
+
E a1: 5
|
180
|
+
}
|
181
|
+
@ anno
|
182
|
+
|F bla
|
183
|
+
))
|
184
|
+
end
|
185
|
+
|
186
|
+
def assert_context(expected, text)
|
187
|
+
# remove first and last lines
|
188
|
+
# these are empty because of the use of %Q
|
189
|
+
exp_lines = expected.split("\n")[1..-2]
|
190
|
+
exp_col = exp_lines.last.index("|")
|
191
|
+
exp_lines.last.sub!("|","")
|
192
|
+
in_lines = text.split("\n")[1..-2]
|
193
|
+
in_col = in_lines.last.index("|")
|
194
|
+
in_lines.last.sub!("|","")
|
195
|
+
ctx = RText::Frontend::Context.new
|
196
|
+
lines, out_col = ctx.extract(in_lines, in_col)
|
197
|
+
assert_equal exp_lines, lines
|
198
|
+
if exp_col && in_col
|
199
|
+
assert_equal exp_col, out_col
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
|