Sentence maker with thesaurus

Posted on

Problem

I’m teaching myself Ruby by rewriting PHP solutions, such as this one. The program should match words in a sentence with a dictionary of synonyms and then make combinations with them.

dict = {
    'hello' => ['hey', 'what's up'],
    'name' => ['nomenclature', 'epithet']
}

str = 'hello, my name is'

class SentenceMaker
    def initialize str, dict
        @thesaurus = []
        @template = str.gsub(/w+/) {|match|
            if (dict[match])
                @thesaurus.push dict[match]
                '%%%d$s' % @thesaurus.length
            else
                match
            end
        }
    end

    def each
        @thesaurus.first.product(*@thesaurus.slice(1..-1)).each {|repl|
            yield @template % repl
        }
    end
end

SentenceMaker.new(str, dict).each {|sentence|
    puts sentence
}

Example output

hey, my nomenclature is
hey, my epithet is
what's up, my nomenclature is
what's up, my epithet is

Does this make enough use of the language expressions, or did I miss a few things?

Solution

Overall, it’s pretty good. My comments are:

  • Use do/end for multiline blocks.
  • Typical Ruby style is a 2-space indent.
  • I think @thesaurus.drop(1) looks a bit better than @thesaurus.slice(1..-1)
  • match is not a good local variable name, word is more descriptive
  • Template is too complicated: you can just use multiple %s placeholders with an array of Strings.

I’m not commenting too much on the algorithm, since you weren’t asking, but it seems a bit complicated. I’d be tempted to try simplifying it a bit.

Here’s your code with the above changes applied:

dict = {
  'hello' => ['hey', 'what's up'],
  'name' => ['nomenclature', 'epithet'],
}

str = 'hello, my name is'

class SentenceMaker
  def initialize str, dict
    @thesaurus = []
    @template = str.gsub(/w+/) do |word|
      if (dict[word])
        @thesaurus.push dict[word]
        '%s'
      else
        word
      end
    end
  end

  def each
    @thesaurus.first.product(*@thesaurus.drop(1)).each do |repl|
      yield @template % repl
    end
  end
end

SentenceMaker.new(str, dict).each {|sentence|
  puts sentence
}

Leave a Reply

Your email address will not be published. Required fields are marked *