Class: String

Inherits:
Object show all
Defined in:
lib/sequence_logo/ytilib/addon.rb,
lib/sequence_logo/ytilib/addon.rb

Overview

String.class_eval do

def to_id
  return self.gsub(/[^.\w]/, '_') 
end

end

Direct Known Subclasses

IUPAC

Instance Method Summary collapse

Instance Method Details

#complObject Also known as: comp, complement



65
66
67
# File 'lib/sequence_logo/ytilib/addon.rb', line 65

def compl
  return self.tr("acgtACGT", "tgcaTGCA")
end

#compl!Object Also known as: comp!, complement!



60
61
62
63
# File 'lib/sequence_logo/ytilib/addon.rb', line 60

def compl!
  self.tr!("acgtACGT", "tgcaTGCA")
  return self
end

#prev(collapse = false) ⇒ Object Also known as: pred

The opposite of String::next / String::succ. It is impossible to be a complete opposite because both “9”.next = “10” and “09”.next = “10”; if going backwards from “10” there’s no way to know whether the result should be “09” or “9”. Where the first ranged character is about to underflow and the next character is within the same range the result is shrunk down - that is, “10” goes to “9”, “aa” goes to “z”; any non- range prefix or suffix is OK, e.g. “+!$%10-=+” goes to “+!$%9-=+”. Items in the middle of a string don’t do this - e.g. “12.10” goes to “12.09”, to match how “next” would work as best as possible.

The standard “next” function works on strings that contain no alphanumeric characters, using character codes. This implementation of “prev” does not work on such strings - while strings may contain any characters you like, only the alphanumeric components are operated upon.

Should total underflow result, “nil” will be returned - e.g. “00”.prev returns ‘nil’, as does “a”.prev. This is done even if there are other characters in the string that were not touched - e.g. “+0.0”.prev also returns “nil”. Broadly speaking, a “nil” return value is used for any attempt to find the previous value of a string that could not have been generated using “next” in the first place.

As with “next” sometimes the result of “prev” can be a little obscure so it is often best to try out things using “irb” if unsure. Note in particular that software revision numbers do not necessarily behave predictably, because they don’t with “next”! E.g. “12.4.9” might go to “12.4.10” for a revision number, but “12.4.9”.next = “12.5.0”. Thus “12.5.0”.prev = “12.4.9” and “12.4.10”.prev = “12.4.09” (because the only way to make “12.4.10” using “next” is to start at “12.4.09”).

Since ‘succ’ (successor) is an alias for ‘next’, so ‘pred’ (predecessor) is an alias for ‘prev’.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/sequence_logo/ytilib/addon.rb', line 132

def prev(collapse = false)
  str        = self.dup
  early_exit = false
  any_done   = false
  ranges     = [
                 ('0'[0]..'9'[0]),
                 ('a'[0]..'z'[0]),
                 ('A'[0]..'Z'[0]),
                 nil
               ]

  # Search forward for the first in-range character. If found check
  # to see if that character is "1", "a" or "A". If it is, record
  # its index (from 0 to string length - 1). We'll need this if
  # underflows wrap as far as the found byte because in that case
  # this first found byte should be deleted ("aa..." -> "z...",
  # "10..." -> "9...").

  first_ranged = nil

  for index in (1..str.length)
    byte = str[index - 1]

    # Determine whether or not the current byte is a number, lower case
    # or upper case letter. We expect 'select' to only find one matching
    # array entry in 'ranges', thus we dereference index 0 after the
    # 'end' to put a matching range from within 'ranges' into 'within',
    # or 'nil' for any unmatched byte.

    within = ranges.select do |range|
      range.nil? or range.include?(byte)
    end [0]

    unless within.nil?
      case within.first
        when '0'[0]
          match_byte = '1'[0]
        else
          match_byte = within.first
      end

      first_ranged = index - 1 if (byte == match_byte)
      first_within = within
      break
    end
  end

  for index in (1..str.length)

    # Process the input string in reverse character order - fetch the
    # bytes via negative index.

    byte = str[-index]

    within = ranges.select do |range|
      range.nil? or range.include?(byte)
    end [0]

    # Skip this letter unless within a known range. Otherwise note that
    # at least one byte was able to be processed.

    next if within.nil?
    any_done = true

    # Decrement the current byte. If it is still within its range, set
    # the byte and bail out - we're finished. Flag the early exit. If
    # the byte is no longer within range, wrap the character around
    # and continue the loop to carry the decrement to an earlier byte.

    byte = byte - 1

    if (within.include? byte)
      str[-index] = byte
      early_exit  = true
      break
    else
      str[-index] = within.last

      # If we've just wrapped around a character immediately after the
      # one found right at the start ('0', 'a' or 'A') then this first
      # ranged character should be deleted (so "10" -> "09"

      if (first_ranged != nil and first_within.include?(byte + 1) and (first_ranged - str.length) == -(index + 1))
        str.slice!(-(index + 1))
        early_exit = true
        break
      end
    end

  end # From outer 'for' loop

  # If we did process at least one byte but we did not exit early, then
  # the loop completed due to carrying a decrement to other bytes. This
  # means an underflow condition - return 'nil'.

  if (any_done == true and early_exit == false)
    return nil
  else
    return str
  end
end

#prev!Object Also known as: pred!

As (extended) String::pred / String::prev, but modifies the string in place rather than returning a copy. If underflow occurs, the string will be unchanged. Returns ‘self’.



238
239
240
241
242
# File 'lib/sequence_logo/ytilib/addon.rb', line 238

def prev!
  new_str = prev
  self.replace(new_str) unless new_str.nil?
  return self
end

#revcompObject



74
75
76
# File 'lib/sequence_logo/ytilib/addon.rb', line 74

def revcomp
  return comp.reverse
end

#revcomp!Object



78
79
80
# File 'lib/sequence_logo/ytilib/addon.rb', line 78

def revcomp!
  return comp!.reverse!
end

#to_idObject



82
83
84
# File 'lib/sequence_logo/ytilib/addon.rb', line 82

def to_id
  return self.gsub(/[^.\w]/, '_').upcase
end