Module: PokePaste

Defined in:
lib/pokepaste.rb,
lib/pokepaste/team.rb,
lib/pokepaste/pokemon.rb

Defined Under Namespace

Classes: Pokemon, Team

Class Method Summary collapse

Class Method Details

.fetch(str) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/pokepaste.rb', line 90

def self.fetch(str)
  input_url = URI.parse(str)
  unless [nil, "pokepast.es"].include? input_url.host
    raise ArgumentError, "invalid URL; must be valid pokepast.es URL or path, received '#{str}'"
  end

  path = (input_url.host ? input_url.path : str).gsub /^\//, ""
  if path.empty?
    raise ArgumentError, "invalid URL; no paste ID found in '#{str}'"
  end

  # The paste is in <article> tags
  paste_content = URI.open("https://pokepast.es/#{path}").read.
                      slice(/(?<=\<article\>)[\S\s]*(?=\<\/article\>)/)

  unless paste_content
    raise OpenURI::HTTPError.new "no paste found at '#{str}'", 404
  end

  # Removing all HTML tags is sufficient to pass the string to the parser
  parse paste_content.gsub(/\<\/?[^\>]+\>/, "")
end

.parse(paste) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/pokepaste.rb', line 7

def self.parse(paste)
  # Each paragraph is a Pokémon (separated by 1 or more blank lines)
  paragraphs = paste.strip.split(/\n\s*\n/).map { |p| p.split("\n").map &:strip }

  team = PokePaste::Team.new

  paragraphs.each do |paragraph|
    # Line 1 can contain species, nickname, gender, and item in format like:
    #   Bud (Bulbasaur) (M) @ Life Orb
    # Only the species is required, however
    line1 = paragraph.shift
    before_at, item = line1.split /\s+@\s+/

    # Now work from right to left, parsing off the parts in parens

    # Set the gender to nil, :male, or :female
    if gender = before_at.slice!(/\s*\((m(ale)?|f(emale)?)\)$/i)
      # Get rid of the parens
      [/^\s*\(/, /\)$/].each { |regex| gender.slice! regex }
      gender = PokePaste::Pokemon.gender_abbrs[gender.downcase[0].to_sym]
    end

    # This regex requires a space between the nickname and opening paren
    if species = before_at.slice!(/\s+\([^\)]+\)$/i)
      # We found the species inside parens, which means a nickname is present
      [/^\s*\(/, /\)$/].each { |regex| species.slice! regex }
      nickname = before_at
    else
      # Otherwise all that remains is the species, and there is no nickname
      species = before_at
      nickname = nil
    end

    pkmn = PokePaste::Pokemon.new species: species, nickname: nickname,
                                  item: item, gender: gender

    # Pull the moves out
    pkmn.moves, paragraph = paragraph.partition { |line| line =~ /^\s*-/ }
    if pkmn.moves.any?
      pkmn.moves.map! do |line|
        move_slot = line.sub /^\s*-\s*/, ""
        move_slot.include?("/") ? move_slot.split(/\s*\/\s*/) : move_slot
      end
    end

    # Pull the nature out. If there are multiple, the first is used
    nature_line, paragraph = paragraph.partition { |line| line =~ /nature\s*$/i }
    if nature_line.any?
      pkmn.nature = nature_line.first.sub(/\s*nature\s*$/i, "").downcase.to_sym
    end

    # All that we're left with at this point are attributes that are denoted with
    # the syntax "Attribute: Value". Let's loop over them and parse the attribute
    paragraph.each do |line|
      attribute, value = line.split /\s*:\s*/, 2
      attribute = attribute.downcase.gsub(/\s+/, "_").to_sym

      # At this point attribute will be a symbol with the snake_case approximation
      # of whatever was before the first ":" in the string. If we know what it does,
      # we can manipulate it as desired, otherwise just let it through as a string.
      # This is intended to be a flexible format.
      if i[evs ivs].include?(attribute)
        data = value.split /\s*\/\s*/
        data.map { |d| d.split /\s+/, 2 }.each do |value, stat|
          current_value = pkmn.send attribute
          current_value[stat.downcase.to_sym] = value.to_i
          pkmn.send "#{attribute}=", current_value
        end
      elsif i[level happiness].include?(attribute)
        pkmn.send "#{attribute}=", value.to_i
      elsif attribute == :shiny
        pkmn.shiny = %w[yes true].include?(value.downcase)
      else
        pkmn.send "#{attribute}=", value
      end
    end

    team << pkmn
  end

  team
end