Class: TracLang::Form
- Inherits:
-
Object
- Object
- TracLang::Form
- Defined in:
- lib/trac_lang/form.rb
Overview
A form is a defined string in TRAC, along with spaces in it for the insertion of parameters.
Defined Under Namespace
Classes: EndOfStringError
Instance Attribute Summary collapse
-
#segments ⇒ Object
readonly
Segment positions of form.
-
#value ⇒ Object
readonly
String value of form.
Instance Method Summary collapse
-
#call_character ⇒ Object
Returns the character being pointed to and moves the pointer one unit to the right.
-
#call_lookup(*args) ⇒ Object
Returns form string with segment gaps filled with the given arguments.
-
#call_n(nstr) ⇒ Object
Returns the given number of characters starting at the current pointer.
-
#call_return ⇒ Object
Returns the pointers to the start of the form.
-
#call_segment ⇒ Object
Returns characters between the current pointer and the next segment gap.
-
#find(search, start = 0) ⇒ Object
Finds the given search string in the string portion of the form, starting at the given space.
-
#find_chars(start) ⇒ Object
Returns characters from the given position to the next segment gap.
-
#format ⇒ Object
Find format of args that works.
-
#in_neutral(search) ⇒ Object
Searches for the given string in the form.
-
#increment(n = 1) ⇒ Object
Increments the character pointer by the given amount.
-
#initialize(value) ⇒ Form
constructor
Creates a new form with the given value.
-
#matched_pair_used?(open, close) ⇒ Boolean
Tests if matched pair of symbols is used anywhere in this form.
-
#max_punch ⇒ Object
Finds the biggest punch index.
-
#punch(punch_in, n) ⇒ Object
Adds segement gaps for one punch.
-
#punched ⇒ Object
Checks if any punches have been done on this form.
-
#segment_string(*punches) ⇒ Object
Add segment gaps for multiple punches.
-
#special_used?(char) ⇒ Boolean
Test if given special character is used anywhere in this form.
-
#to_s ⇒ Object
Converts this form into a string for display.
-
#to_trac(name) ⇒ Object
Converts current state of this form into TRAC commands.
Constructor Details
#initialize(value) ⇒ Form
Creates a new form with the given value.
21 22 23 24 25 26 27 28 29 |
# File 'lib/trac_lang/form.rb', line 21 def initialize(value) @value = value @segments = Array.new(@value.length + 1) { [] } # character pointer is the index into the segments array @cp = 0 # segment pointer is the index into @segments[@cp] # if @sp == @segments[@cp].lenth then it is pointing to @value[@cp] @sp = 0 end |
Instance Attribute Details
#segments ⇒ Object (readonly)
Segment positions of form. This is stored as an array of arrays. Each position in the array corresponds to a character in the form string, with an additional entry at the end. If the entry is non-empty it will have a list of the segment numbers at that location.
15 16 17 |
# File 'lib/trac_lang/form.rb', line 15 def segments @segments end |
#value ⇒ Object (readonly)
String value of form.
18 19 20 |
# File 'lib/trac_lang/form.rb', line 18 def value @value end |
Instance Method Details
#call_character ⇒ Object
Returns the character being pointed to and moves the pointer one unit to the right. Raises a EndOfStringError if the pointer is already at the end of the form.
90 91 92 93 94 95 |
# File 'lib/trac_lang/form.rb', line 90 def call_character(*) raise EndOfStringError if @cp == @value.length result = @value[@cp, 1] increment result end |
#call_lookup(*args) ⇒ Object
Returns form string with segment gaps filled with the given arguments.
174 175 176 177 178 179 180 181 182 |
# File 'lib/trac_lang/form.rb', line 174 def call_lookup(*args) trimmed = @segments.dup # trim off everything before current pointer trimmed.slice!(0...@cp) unless @cp == 0 trimmed[0].slice!(0...@sp) unless trimmed[0].empty? || @sp == 0 trimmed.map.with_index do |a, i| a.map { |v| args[v - 1] || '' }.join + (@value[@cp + i] || '') end.join end |
#call_n(nstr) ⇒ Object
Returns the given number of characters starting at the current pointer. If the number is negative, returns characters before the current pointer, but in the same order the characters are in the form. Raises an EndOfStringError if a negative number is given and you are at the start of the form, or if a positive number is given and you are at the end of the form. A value of zero can be given to test where the pointer is without changing it.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/trac_lang/form.rb', line 104 def call_n(nstr, *) tn = TracLang::Decimal.new(nstr) n = tn.value if tn.negative? raise EndOfStringError if @cp == 0 && @sp == 0 # move left of seg gaps @sp = 0 return '' if n == 0 raise EndOfStringError if @cp == 0 n = -@cp if n < -@cp result = @value.slice(@cp + n, -n) increment(n) else raise EndOfStringError if @value.length - @cp == 0 && @sp == @segments[@cp].length # move right of seg gaps @sp = @segments[@cp].length return '' if n == 0 raise EndOfStringError if @value.length - @cp == 0 n = @value.length - @cp if n > @value.length - @cp result = @value.slice(@cp, n) increment(n) end result end |
#call_return ⇒ Object
Returns the pointers to the start of the form.
82 83 84 85 |
# File 'lib/trac_lang/form.rb', line 82 def call_return(*) @sp = 0 @cp = 0 end |
#call_segment ⇒ Object
Returns characters between the current pointer and the next segment gap.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/trac_lang/form.rb', line 156 def call_segment(*) raise EndOfStringError if @cp == @value.length + 1 # would this ever be true? # on a character if @sp == @segments[@cp].length # may be zero raise EndOfStringError if @cp == @value.length result = find_chars(@cp) @cp += result.length # need check if you're at end of string @sp = @segments[@cp].empty? ? 0 : 1 # else within segment list else result = '' @sp += 1 end result end |
#find(search, start = 0) ⇒ Object
Finds the given search string in the string portion of the form, starting at the given space. A successful match cannot span segment gaps.
33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/trac_lang/form.rb', line 33 def find(search, start = 0) loop do i = @value.index(search, start) return nil unless i # don't find over segment boundaries boundary = @segments.slice(i + 1, search.length - 1) unless boundary.all? { |v| v.empty? } start = i + 1 next end return i end end |
#find_chars(start) ⇒ Object
Returns characters from the given position to the next segment gap.
148 149 150 151 152 |
# File 'lib/trac_lang/form.rb', line 148 def find_chars(start) # don't test start position because you might be at the end of the segment list len = 1 + @segments[(start + 1)..-2].take_while { |s| s.empty? }.count @value.slice(start, len) end |
#format ⇒ Object
Find format of args that works
207 208 209 210 211 212 213 |
# File 'lib/trac_lang/form.rb', line 207 def format pair = [['<','>'],['[',']'],['{','}']].find { |p| !matched_pair_used?(*p) } return pair if pair special = (126..255).find { |n| !special_used?(n.chr) } return [special.chr, special.chr] if special # what to do if nothing works? end |
#in_neutral(search) ⇒ Object
Searches for the given string in the form. If found, returns all characters between the current pointer and the start of the match, while moving the character pointer past the match. Raises an EndOfStringError if you are at the end of the form or no match is found. An empty search string counts as always not matching.
134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/trac_lang/form.rb', line 134 def in_neutral(search, *) raise EndOfStringError if @cp == @value.length || search.empty? found = find(search, @cp) if found result = @value[@cp...found] increment(found - @cp + search.length) return result else # form pointer is not moved if not found raise EndOfStringError end end |
#increment(n = 1) ⇒ Object
Increments the character pointer by the given amount.
74 75 76 77 78 79 |
# File 'lib/trac_lang/form.rb', line 74 def increment(n = 1) @cp += n @cp = @value.length if @cp > @value.length @cp = 0 if @cp < 0 @sp = n > 0 ? 0 : @segments[@cp].length end |
#matched_pair_used?(open, close) ⇒ Boolean
Tests if matched pair of symbols is used anywhere in this form. Used to find an unused pair for writing this form to a file.
196 197 198 |
# File 'lib/trac_lang/form.rb', line 196 def matched_pair_used?(open, close) max_punch.times.map { |i| "#{open}#{i + 1}#{close}" }.any? { |s| @value.include?(s) } end |
#max_punch ⇒ Object
Finds the biggest punch index.
190 191 192 |
# File 'lib/trac_lang/form.rb', line 190 def max_punch @segments.map { |s| s.max }.compact.max end |
#punch(punch_in, n) ⇒ Object
Adds segement gaps for one punch.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/trac_lang/form.rb', line 48 def punch(punch_in, n) return if punch_in.empty? start = 0 punch = punch_in.dup len = punch.length loop do found = find(punch) break unless found if @segments[found].empty? @segments.slice!(found, len) @segments[found].unshift(n) else @segments[found].push(n) @segments[found] += @segments[found + len] @segments.slice!(found + 1, len) end @value.slice!(found, len) end end |
#punched ⇒ Object
Checks if any punches have been done on this form.
185 186 187 |
# File 'lib/trac_lang/form.rb', line 185 def punched @segments.any? { |s| !s.empty? } end |
#segment_string(*punches) ⇒ Object
Add segment gaps for multiple punches.
69 70 71 |
# File 'lib/trac_lang/form.rb', line 69 def segment_string(*punches) punches.each.with_index { |p, n| punch(p, n + 1) } end |
#special_used?(char) ⇒ Boolean
Test if given special character is used anywhere in this form. Used to find an unused special character for writing this form to a file.
202 203 204 |
# File 'lib/trac_lang/form.rb', line 202 def special_used?(char) max_punch.times.map { |i| "#{char}#{i + 1}" }.any? { |s| @value.include?(s) } end |
#to_s ⇒ Object
Converts this form into a string for display. Follows format of TRAC display defined in language definition.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/trac_lang/form.rb', line 236 def to_s str = '' @segments.each.with_index do |s, cp| s.each.with_index do |n, sp| str += '<^>' if @cp == cp && @sp == sp str += "<#{n}>" end str += '<^>' if @cp == cp && @sp == s.length if cp < @value.length c = @value[cp] # escape non-printable characters str << (c =~ /[[:print:]]/ ? c : sprintf("\\x%02.2x", c.ord)) end end str end |
#to_trac(name) ⇒ Object
Converts current state of this form into TRAC commands.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/trac_lang/form.rb', line 216 def to_trac(name) cp, sp = @cp, @sp @cp, @sp = 0, 0 if punched pair = format args = max_punch.times.map { |i| "#{pair[0]}#{i + 1}#{pair[1]}"} trac = "#(DS,#{name},#{call_lookup(*args)})\n" trac += "#(SS,#{name},#{args.join(',')})\n" unless args.empty? else trac = "#(DS,#{name},#{@value})\n" end trac += "#(CN,#{name},#{cp})\n" unless cp == 0 trac += "#(CS,#{name})" * sp + "\n" unless sp == 0 trac += "\n" @cp, @sp = cp, sp trac end |