Class: JMadlibs

Inherits:
Object
  • Object
show all
Defined in:
lib/jmadlibs.rb

Instance Method Summary collapse

Constructor Details

#initialize(pattern = nil, library = nil, variantString = "") ⇒ JMadlibs

Returns a new instance of JMadlibs.



27
28
29
30
31
32
33
34
# File 'lib/jmadlibs.rb', line 27

def initialize(pattern=nil, library=nil, variantString = "")
  @loglevels = {0 => "NONE", 1 => "ERROR", 2 => "WARN", 3 => "INFO", 4 => "DEBUG", 5 => "ALL"}
  @loglevel = 3
  @rng = Random.new
  setPattern(pattern)
  setLibrary(library)
  setVariants(variantString)
end

Instance Method Details

#addList(name, wordlist) ⇒ Object



43
44
45
46
47
# File 'lib/jmadlibs.rb', line 43

def addList(name, wordlist)
  if @library.nil? then @library = {} end
  log "Adding list '" + name + "'", "DEBUG"
  @library[name] = wordlist
end

#anify(word) ⇒ Object

If word begins with a vowel, prefix ‘an ’, else prefix ‘a ’



101
102
103
104
105
106
107
108
109
# File 'lib/jmadlibs.rb', line 101

def anify(word) # If word begins with a vowel, prefix 'an ', else prefix 'a '
  if (/^[aeiou]/.match(word).nil?)
    result = "a " + word
  else
    result = "an " + word
  end

  return result
end

#generateObject



391
392
393
394
395
396
397
398
399
400
401
# File 'lib/jmadlibs.rb', line 391

def generate
  if @library.nil?
    log "No library defined.", "WARN"
 return nil
  elsif @pattern.nil?
    log "No pattern defined.", "WARN"
 return nil
  else
    return parse_pattern(@pattern)
  end
end

#getSpecified(word, specifier = nil) ⇒ Object

get the correct representation of a word



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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
# File 'lib/jmadlibs.rb', line 111

def getSpecified(word, specifier = nil) # get the correct representation of a word
  #TODO: Convert ex. marry^marries^married^marrying to specified subword, return first if no specifier

  # find default
  options = word.count("\^")

  if options == 0 # no variants exist
    return word
  end

  default = word[0..word.index("^")-1]

  if specifier.nil?
    return default
  end

  variant = 0

  if !specifier.index(/[0-9]/).nil? 
    variant = specifier.to_i
  else
    variant = @variants.index(specifier)
  end

  if variant.nil?
    log "Unknown variant identifier '" + specifier + "', using default.", 3
    return default
  end

  start = 0

  if variant >= options 
    log "Unknown variant identifier '" + variant.to_s + "', using default.", 3
    return default
  end


  for i in 0..variant # find start of correct option
     start = word.index("^", start+1)
  end

  finish = word.index("^", start+1)

  result = ""

  if finish.nil?
    result = word[start+1..-1]
  else
    result = word[start+1..finish-1]
  end

  if result.empty?
    return default
  else
     return result
  end
end

#loadList(filename) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/jmadlibs.rb', line 71

def loadList(filename)
  if File.file?(filename)
    log "Loading word lists from " + filename, "INFO"
    @library = {}
    currentList = ""
    currentListContents = []

    File.foreach(filename).with_index do |line|
      line = line.strip
      if line != "" and !line.start_with?('#')
        matched = /^==(.+)==$/.match(line)
        if !matched.nil? # new list identifier
          if currentList != "" # save old list, if one exists.
            addList(currentList, currentListContents)
          end
          currentList = matched[1] # update working targets for new list
          currentListContents = []
        elsif currentList == "" # we have no current list; this must be a pattern
          setPattern(line)
        else # word to be added to current list
          currentListContents.push(line)
        end
      end
    end
    addList(currentList, currentListContents)
  else
    log "Unable to open file.", "WARN"
  end
end

#log(msg, priority = 5) ⇒ Object



36
37
38
39
40
41
# File 'lib/jmadlibs.rb', line 36

def log(msg, priority=5)
  if priority.is_a? String then priority = @loglevels.key(priority) end
  if priority <= @loglevel
 puts "JMadlibs: [" + @loglevels[priority] + "] " + msg
  end
end

#parse_pattern(target) ⇒ Object



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/jmadlibs.rb', line 330

def parse_pattern(target)
  tokens = []
  flags = []
  escaped = false

  while target.length > 0
    ind = target.index /[<{\[]/

    if ind.nil? # only plain text remains
      tokens << target
      target = ""
      flags << "p"

    elsif ind > 0 # plain text with some other token following
      tokens << target.slice(0,ind)
      target = target.slice(ind, target.length - ind)
      flags << "p"

    else # non-plaintext token
      type = ""

      if target.slice(0) == "<"
        ind = target.index(">")
        type = "s"
      elsif target.slice(0) == "{"
        ind = target.index("}")
        type = "a"
      elsif target.slice(0) == "["
        ind = target.index("]")
        type = "o"
      end

      if ind.nil?
        log "'" + target +"' escaped or missing terminator, treating as plaintext.", "INFO"
        tokens << target
        target = ""
        flags << "p"
      else
        tokens << target.slice(1, ind-1)
        target = target.slice(ind+1, target.length - ind+1)
        flags << type
      end
    end
  end

  # parse tokens
  tokens.each_with_index { |token, index|
    if flags[index] == "a"
      tokens[index] = resolve_alternative(token)
    elsif flags[index] == "o"
      tokens[index] = resolve_optional(token)
    elsif flags[index] == "s"
      tokens[index] = resolve_substitution(token)
    end
  }

  # rebuild string
  result = tokens.join
  return result
end

#pluralise(word) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/jmadlibs.rb', line 169

def pluralise(word)
  # TODO
  # add s by default
  # (lf)(fe?) -> ves
  # y -> ies
  # o -> oes
  # (se?)(sh)(ch)

  # this is a pretty big problem!  POssibly solvable with getSpecified instead.
  return word
end

#resolve_alternative(target) ⇒ Object



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/jmadlibs.rb', line 289

def resolve_alternative(target)
  options = []
  while target.length > 0 # split into options
    ind = target.index /\|/ # needs rewriting to parse (a|(ba|bb)) and similar

    if ind.nil? # only one option
      options << target
      target = ""
    else
      options << target.slice(0, ind)
      target = target.slice(ind+1, target.length - ind - 1)
    end
  end

  result = options.sample(random: @rng)
  return parse_pattern(result)
end

#resolve_optional(target) ⇒ Object



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/jmadlibs.rb', line 307

def resolve_optional(target)
  chance = 50

  ind = target.index("%") # specified chance?

  if !ind.nil?
    chance = target.slice(ind+1, target.length - ind - 1).to_i
    target = target.slice(0, ind)
  end

  result = ""

  if @rng.rand(100) <= chance
    result = target
  end

  return parse_pattern(result)
end

#resolve_substitution(target) ⇒ Object



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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/jmadlibs.rb', line 181

def resolve_substitution(target)
  up = false
  specifiers = ""

  # do we need to do post-processing?
  post = target.rindex(/\$[a-zA-Z0-9]+/)

  if !post.nil?
    specifiers = target.slice(post+1, target.length - post - 1)
    variant = specifiers.scan(/[a-z0-9]/)
    specifiers = specifiers.scan(/[A-Z]/)
    target = target.slice(0, post)
  end

  if !(/^[A-Z]/.match(target).nil?) # do we need to capitalise?
    target = target.downcase
    up = true
  end

  # are we selecting from multiple lists?
  mult = target.index /\+/

  if mult.nil? # only one list
    if @library[target].nil?
      log "Missing wordlist: " + target, 2
      return "MISSING"
    end
    result = parse_pattern(@library[target].sample(random: @rng))

  else # more than one list
    multlist = []
    listnames = []

    if false # testing new method

    # as long as we still have alternatives, keep adding them to listnames
    while !mult.nil?
      listnames << target.slice(0, mult)
  target = target.slice(mult+1, target.length - mult - 1)
      mult = target.index /\+/
    end
    listnames << target # append final alternative

    # combine lists for sampling
    listnames.each do |list|
      if !@library[list].nil? then multlist += @library[list] end
    end

    if multlist.length == 0 # no valid options found
      log "Missing wordlist: " + target, 2
      return "MISSING"
    end
    result = parse_pattern(multlist.sample(random: @rng))

    else # Test of new routine for sampling multiple lists
      while !mult.nil?
        listnames << target.slice(0, mult)
        target = target.slice(mult+1, target.length - mult - 1)
        mult = target.index /\+/
      end
      listnames << target # append final alternative

      # Find total count of options
      max = 0

      listnames.each do |list|
        if !@library[list].nil? then max += @library[list].length end
      end

      # Pick index within overall size
      index = @rng.rand(max)

      # iterate through lists until we find the list the index fits into
      listnames.each do |list|
        if index >= @library[list].length # Not in this list, so discard its indices
          index -= @library[list].length
        else
          result = parse_pattern(@library[list][index]) # in this list; return index
          break
        end            
      end
    end
  end

  # Dealing with possible variant suffixes

  if result.count("\^") > 0 # if we have options...
    if !variant.nil? and variant.length > 0 # get variant if it exists
      variant = variant.slice!(0)
      result = getSpecified(result, variant)
    else # get the default
      result = getSpecified(result)
    end
  end

  # do post-processing

  if specifiers.include? "A"
    result = anify(result)
  end

  if specifiers.include? "U"
    result[0] = result[0].upcase
  end

  return result
end

#sampledict(target) ⇒ Object



326
327
328
# File 'lib/jmadlibs.rb', line 326

def sampledict(target)
  return resolve_substitution(target)
end

#setLibrary(library) ⇒ Object



54
55
56
57
58
59
# File 'lib/jmadlibs.rb', line 54

def setLibrary(library)
  if !library.nil?
    log "Library updated", "DEBUG"
    @library = library
  end
end

#setLogLevel(loglevel) ⇒ Object



65
66
67
68
69
# File 'lib/jmadlibs.rb', line 65

def setLogLevel(loglevel)
  if loglevel.is_a? String then loglevel = @loglevels.key(loglevel) end
  @loglevel = loglevel
  log "Loglevel set to '" + @loglevels[loglevel] +"'", "INFO"
end

#setPattern(pattern) ⇒ Object



49
50
51
52
# File 'lib/jmadlibs.rb', line 49

def setPattern(pattern)
  if !pattern.nil? then log "Pattern set to '" + pattern + "'", "DEBUG" end
  @pattern = pattern
end

#setVariants(variantString) ⇒ Object



61
62
63
# File 'lib/jmadlibs.rb', line 61

def setVariants(variantString)
  @variants = variantString
end