Class Irc::Bot::MessageTemplate
In: lib/rbot/messagemapper.rb
Parent: Object
BasicUserMessage JoinMessage NamesMessage WhoisMessage ModeChangeMessage KickMessage MotdMessage QuitMessage BanlistMessage UserMessage NoSuchTargetMessage TopicMessage NickMessage WelcomeMessage UnknownMessage InviteMessage PartMessage NetmaskList UserList ArrayOf ChannelList Netmask User\n[lib/rbot/botuser.rb\nlib/rbot/irc.rb] Channel Singleton RfcCasemap StrictRfcCasemap AsciiCasemap Casemap PrivMessage NoticeMessage TokyoCabinet::BDB CIBDB Btree CIBtree Socket MessageQueue QueueRing Client DBHash\n[lib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] DBTree\n[lib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] Server NetmaskDb Bot\n[lib/rbot/botuser.rb\nlib/rbot/config.rb\nlib/rbot/ircbot.rb\nlib/rbot/language.rb\nlib/rbot/message.rb\nlib/rbot/messagemapper.rb\nlib/rbot/plugins.rb\nlib/rbot/rbotconfig.rb\nlib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] lib/rbot/ircsocket.rb lib/rbot/rfc2812.rb lib/rbot/registry/tc.rb lib/rbot/irc.rb lib/rbot/maskdb.rb lib/rbot/message.rb lib/rbot/messagemapper.rb lib/rbot/botuser.rb lib/rbot/registry/tc.rb (null) BotConfig PKGConfig ServerOrCasemap Irc dot/m_35_0.png

MessageTemplate is the class that holds the actual message template map()’d by a BotModule and handled by a MessageMapper

Methods

Attributes

botmodule  [R] 
defaults  [R] 
items  [R] 
options  [R] 
regexp  [R] 
template  [R] 

Public Class methods

Create a new MessageTemplate associated to BotModule botmodule, with template template and options opts

[Source]

     # File lib/rbot/messagemapper.rb, line 411
411:     def initialize(botmodule, template, hash={})
412:       raise ArgumentError, "Third argument must be a hash!" unless hash.kind_of?(Hash)
413:       @defaults = hash[:defaults].kind_of?(Hash) ? hash.delete(:defaults) : {}
414:       @requirements = hash[:requirements].kind_of?(Hash) ? hash.delete(:requirements) : {}
415:       @template = template
416:       case botmodule
417:       when String
418:         @botmodule = botmodule
419:       when Plugins::BotModule
420:         @botmodule = botmodule.name
421:       else
422:         raise ArgumentError, "#{botmodule.inspect} is not a botmodule nor a botmodule name"
423:       end
424: 
425:       self.items = template
426:       # @dyn_items is an array of MessageParameters, except for the first entry
427:       # which is the template
428:       @dyn_items = @items.collect { |it|
429:         if it.kind_of?(Symbol)
430:           i = it.to_s
431:           opt = MessageParameter.new(i)
432:           if i.sub!(/^\*/,"")
433:             opt.name = i
434:             opt.multi = true
435:           end
436:           opt.default = @defaults[opt.name]
437:           opt.collector = @requirements[opt.name]
438:           opt
439:         else
440:           nil
441:         end
442:       }
443:       @dyn_items.unshift(template).compact!
444:       debug "Items: #{@items.inspect}; dyn items: #{@dyn_items.inspect}"
445: 
446:       self.regexp = template
447:       debug "Command #{template.inspect} in #{@botmodule} will match using #{@regexp}"
448: 
449:       set_auth_path(hash)
450: 
451:       unless hash.has_key?(:action)
452:         hash[:action] = items[0]
453:       end
454: 
455:       @options = hash
456: 
457:       # debug "Create template #{self.inspect}"
458:     end

Public Instance methods

[Source]

     # File lib/rbot/messagemapper.rb, line 645
645:     def  inspectinspect
646:       when_str = @requirements.empty? ? "" : " when #{@requirements.inspect}"
647:       default_str = @defaults.empty? ? "" : " || #{@defaults.inspect}"
648:       "<#{self.class.to_s} #{@items.map { |c| c.inspect }.join(' ').inspect}#{default_str}#{when_str}>"
649:     end

[Source]

     # File lib/rbot/messagemapper.rb, line 499
499:     def items=(str)
500:       raise ArgumentError, "template #{str.inspect} should be a String" unless str.kind_of?(String)
501: 
502:       # split and convert ':xyz' to symbols
503:       items = str.strip.split(/\]?\s+\[?|\]?$/).collect { |c|
504:         # there might be extra (non-alphanumeric) stuff (e.g. punctuation) after the symbol name
505:         if /^(:|\*)(\w+)(.*)/ =~ c
506:           sym = ($1 == ':' ) ? $2.intern : "*#{$2}".intern
507:           if $3.empty?
508:             sym
509:           else
510:             [sym, $3]
511:           end
512:         else
513:           c
514:         end
515:       }.flatten
516:       @items = items
517: 
518:       raise ArgumentError, "Illegal template -- first component cannot be dynamic: #{str.inspect}" if @items.first.kind_of? Symbol
519: 
520:       raise ArgumentError, "Illegal template -- first component cannot be optional: #{str.inspect}" if @items.first =~ /\[|\]/
521: 
522:       # Verify uniqueness of each component.
523:       @items.inject({}) do |seen, item|
524:         if item.kind_of? Symbol
525:           # We must remove the initial * when present,
526:           # because the parameters hash will intern both :item and *item as :item
527:           it = item.to_s.sub(/^\*/,"").intern
528:           raise ArgumentError, "Illegal template -- duplicate item #{it} in #{str.inspect}" if seen.key? it
529:           seen[it] = true
530:         end
531:         seen
532:       end
533:     end

Recognize the provided string components, returning a hash of recognized values, or [nil, reason] if the string isn‘t recognized.

[Source]

     # File lib/rbot/messagemapper.rb, line 581
581:     def recognize(m)
582: 
583:       debug "Testing #{m.message.inspect} against #{self.inspect}"
584: 
585:       matching = @regexp.match(m.message)
586:       return MessageMapper::NoMatchFailure.new(self, m) unless matching
587:       return MessageMapper::PartialMatchFailure.new(self, m) unless matching[0] == m.message
588: 
589:       return MessageMapper::NotPrivateFailure.new(self, m) if @options.has_key?(:private) && !@options[:private] && m.private?
590:       return MessageMapper::NotPublicFailure.new(self, m) if @options.has_key?(:public) && !@options[:public] && !m.private?
591: 
592:       debug_match = matching[1..-1].collect{ |d| d.inspect}.join(', ')
593:       debug "#{m.message.inspect} matched #{@regexp} with #{debug_match}"
594:       debug "Associating #{debug_match} with dyn items #{@dyn_items.join(', ')}"
595: 
596:       options = @defaults.dup
597: 
598:       @dyn_items.each_with_index { |it, i|
599:         next if i == 0
600:         item = it.name
601:         debug "dyn item #{item} (multi-word: #{it.multi?.inspect})"
602:         if it.multi?
603:           if matching[i].nil?
604:             default = it.default
605:             case default
606:             when Array
607:               value = default.clone
608:             when String
609:               value = default.strip.split
610:             when nil, false, []
611:               value = []
612:             else
613:               warning "Unmanageable default #{default} detected for :*#{item.to_s}, using []"
614:               value = []
615:             end
616:             case default
617:             when String
618:               value.instance_variable_set(:@string_value, default)
619:             else
620:               value.instance_variable_set(:@string_value, value.join(' '))
621:             end
622:           else
623:             value = matching[i].split
624:             value.instance_variable_set(:@string_value, matching[i])
625:           end
626:           def value.to_s
627:             @string_value
628:           end
629:         else
630:           if matching[i].nil?
631:             warning "No default value for option #{item.inspect} specified" unless @defaults.has_key?(item)
632:             value = it.default
633:           else
634:             value = it.collect(matching[i])
635:           end
636:         end
637:         options[item] = value
638:         debug "set #{item} to #{options[item].inspect}"
639:       }
640: 
641:       options.delete_if {|k, v| v.nil?} # Remove nil values.
642:       return options
643:     end

[Source]

     # File lib/rbot/messagemapper.rb, line 535
535:     def regexp=(str)
536:       # debug "Original string: #{str.inspect}"
537:       rx = Regexp.escape(str)
538:       # debug "Escaped: #{rx.inspect}"
539:       rx.gsub!(/((?:\\ )*)(:|\\\*)(\w+)/) { |m|
540:         whites = $1
541:         is_single = $2 == ":"
542:         name = $3.intern
543: 
544:         not_needed = @defaults.has_key?(name)
545: 
546:         has_req = @requirements[name]
547:         debug "Requirements for #{name}: #{has_req.inspect}"
548:         case has_req
549:         when nil
550:           sub = is_single ? "\\S+" : ".*?"
551:         when Regexp
552:           # Remove captures and the ^ and $ that are sometimes placed in requirement regexps
553:           sub = has_req.mm_cleanup
554:         when String
555:           sub = Regexp.escape(has_req)
556:         when Array
557:           sub = has_req[0].mm_cleanup
558:         when Hash
559:           sub = has_req[:regexp].mm_cleanup
560:         else
561:           warning "Odd requirement #{has_req.inspect} of class #{has_req.class} for parameter '#{name}'"
562:           sub = Regexp.escape(has_req.to_s) rescue "\\S+"
563:         end
564:         debug "Regexp for #{name}: #{sub.inspect}"
565:         s = "#{not_needed ? "(?:" : ""}#{whites}(#{sub})#{ not_needed ? ")?" : ""}"
566:       }
567:       # debug "Replaced dyns: #{rx.inspect}"
568:       rx.gsub!(/((?:\\ )*)((?:\\\[)+)/, '\2\1')
569:       # debug "Corrected optionals spacing: #{rx.inspect}"
570:       rx.gsub!(/\\\[/, "(?:")
571:       rx.gsub!(/\\\]/, ")?")
572:       # debug "Delimited optionals: #{rx.inspect}"
573:       rx.gsub!(/(?:\\ )+/, "\\s+")
574:       # debug "Corrected spaces: #{rx.inspect}"
575:       # Created message (such as by fake_message) can contain multiple lines
576:       @regexp = /\A#{rx}\z/m
577:     end

[Source]

     # File lib/rbot/messagemapper.rb, line 651
651:     def requirements_for(name)
652:       name = name.to_s.sub(/^\*/,"").intern if (/^\*/ =~ name.inspect)
653:       presence = (@defaults.key?(name) && @defaults[name].nil?)
654:       requirement = case @requirements[name]
655:         when nil then nil
656:         when Regexp then "match #{@requirements[name].inspect}"
657:         else "be equal to #{@requirements[name].inspect}"
658:       end
659:       if presence && requirement then "#{name} must be present and #{requirement}"
660:       elsif presence || requirement then "#{name} must #{requirement || 'be present'}"
661:       else "#{name} has no requirements"
662:       end
663:     end

[Source]

     # File lib/rbot/messagemapper.rb, line 460
460:     def set_auth_path(hash)
461:       if hash.has_key?(:auth)
462:         warning "Command #{@template.inspect} in #{@botmodule} uses old :auth syntax, please upgrade"
463:       end
464:       if hash.has_key?(:full_auth_path)
465:         warning "Command #{@template.inspect} in #{@botmodule} sets :full_auth_path, please don't do this"
466:       else
467:         pre = @botmodule
468:         words = items.reject{ |x|
469:           x == pre || x.kind_of?(Symbol) || x =~ /\[|\]/
470:         }
471:         if words.empty?
472:           post = nil
473:         else
474:           post = words.first
475:         end
476:         if hash.has_key?(:auth_path)
477:           extra = hash[:auth_path]
478:           if extra.sub!(/^:/, "")
479:             pre += "::" + post
480:             post = nil
481:           end
482:           if extra.sub!(/:$/, "")
483:             if words.length > 1
484:               post = [post,words[1]].compact.join("::")
485:             end
486:           end
487:           pre = nil if extra.sub!(/^!/, "")
488:           post = nil if extra.sub!(/!$/, "")
489:           extra = nil if extra.empty?
490:         else
491:           extra = nil
492:         end
493:         hash[:full_auth_path] = [pre,extra,post].compact.join("::")
494:         debug "Command #{@template} in #{botmodule} will use authPath #{hash[:full_auth_path]}"
495:         # TODO check if the full_auth_path is sane
496:       end
497:     end

[Validate]