pokepaste 0.0 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -8
- data/VERSION +1 -1
- data/lib/pokepaste/pokemon.rb +128 -1
- data/lib/pokepaste/{paste.rb → team.rb} +12 -1
- data/lib/pokepaste.rb +105 -3
- data/spec/pokepaste/parser_spec.rb +57 -0
- data/spec/pokepaste/pokemon_spec.rb +92 -0
- data/spec/pokepaste/team_spec.rb +33 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/paste_equality.rb +8 -0
- data/spec/support/test_paste.rb +126 -0
- metadata +13 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00dd0a7de40dd35ecfea44b68923d6670038e9975fea57031d344686eab5be8e
|
4
|
+
data.tar.gz: 1dd51398eaa67e92e7c4be23007c3ef551a4ad59be205978404f47f243d6fea3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d373e26fb2be699c0b083ffa5acfda5543514c5373077b762d35cdc2611cfb7effcea61066cb8719e00fba1dfee4bfe5387ccc77726dd186975ab98bc078ca7
|
7
|
+
data.tar.gz: 4cdae218a9a99a2294085c1a5aafcdab28615c66e87a810952562e12f8946e32bb1b636653a146519bdba63dd1d90292141b41a77c99026c5523ee4e9312796d
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ by Pokémon Showdown and various teambuilders.
|
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
8
|
-
Install with RubyGems:
|
8
|
+
Install with [RubyGems](https://rubygems.org/gems/pokepaste):
|
9
9
|
|
10
10
|
```bash
|
11
11
|
gem install pokepaste
|
@@ -40,17 +40,17 @@ team = PokePaste::fetch("https://pokepast.es/5c46f9ec443664cb")
|
|
40
40
|
team = PokePaste::fetch("5c46f9ec443664cb") # full URL optional
|
41
41
|
```
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
These methods return an instance of `PokePaste::Team`, an Enumerable
|
44
|
+
containing an instance of `PokePaste::Pokemon` for each Pokémon on
|
45
45
|
the team. You can loop over the team as with any Enumerable, and access the
|
46
46
|
data like so:
|
47
47
|
|
48
48
|
```ruby
|
49
49
|
team.each do |pkmn|
|
50
50
|
pkmn.species # required
|
51
|
-
pkmn.nickname # default
|
52
|
-
pkmn.gender # default
|
53
|
-
pkmn.item # default
|
51
|
+
pkmn.nickname # default nil
|
52
|
+
pkmn.gender # default nil
|
53
|
+
pkmn.item # default nil
|
54
54
|
|
55
55
|
# EVs and IVs are hashes with the stat as the key
|
56
56
|
# (:hp, :atk, :def, :spa, :spd, or :spe)
|
@@ -58,7 +58,8 @@ team.each do |pkmn|
|
|
58
58
|
pkmn.ivs[:spa] # default 31
|
59
59
|
|
60
60
|
pkmn.shiny? # default is false
|
61
|
-
pkmn.ability # default is
|
61
|
+
pkmn.ability # default is nil
|
62
|
+
pkmn.tera_type # default is nil
|
62
63
|
pkmn.level # default is 50
|
63
64
|
pkmn.happiness # default is 255
|
64
65
|
pkmn.nature # default is :hardy (neutral nature)
|
@@ -87,6 +88,7 @@ team << PokePaste::Pokemon.new(
|
|
87
88
|
species: "Bulbasaur",
|
88
89
|
nickname: "Bud",
|
89
90
|
ivs: {atk: 0},
|
91
|
+
shiny: true,
|
90
92
|
moves: %w[Tackle Growl]
|
91
93
|
)
|
92
94
|
|
@@ -100,9 +102,18 @@ a paste on [pokepast.es](https://pokepast.es/), you could:
|
|
100
102
|
raw_paste = PokePaste.fetch(url_or_id).to_s
|
101
103
|
```
|
102
104
|
|
105
|
+
This library is purely a parser for the PokéPaste format, it does not contain
|
106
|
+
any data about the Pokémon, whether or not the moves are valid, their
|
107
|
+
abilities, anything like that. You could enter nonsense into any of the given
|
108
|
+
fields and they will be parsed to and from the PokéPaste format happily.
|
109
|
+
Validating anything beyond the syntax of the PokéPaste is left up to the user.
|
110
|
+
|
103
111
|
## License
|
104
112
|
|
105
113
|
This library is released under the MIT license. See the
|
106
|
-
[`LICENSE.md`](https://github.com/vinnydiehl/pokepaste-ruby/blob/
|
114
|
+
[`LICENSE.md`](https://github.com/vinnydiehl/pokepaste-ruby/blob/develop/LICENSE.md)
|
107
115
|
file included with this code or
|
108
116
|
[the official page on OSI](http://opensource.org/licenses/MIT) for more information.
|
117
|
+
|
118
|
+
I am not affiliated with Nintendo, Game Freak, The Pokémon Company, or any of
|
119
|
+
their subsidiaries. This is a free fan-made project. Pokémon is © and ™ Nintendo.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1
|
data/lib/pokepaste/pokemon.rb
CHANGED
@@ -1,9 +1,136 @@
|
|
1
1
|
module PokePaste
|
2
2
|
class Pokemon
|
3
|
-
|
3
|
+
attr_accessor *%i[species nickname gender item evs ivs shiny
|
4
|
+
ability tera_type level happiness nature moves]
|
5
|
+
|
6
|
+
@gender_abbrs = {m: :male, f: :female}
|
7
|
+
class << self
|
8
|
+
attr_accessor :gender_abbrs
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(**attrs)
|
12
|
+
unless attrs[:species]
|
13
|
+
raise ArgumentError, "species required to initialize a PokePaste::Pokemon"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Check types for things expected to be other than strings... everything else will
|
17
|
+
# at worst get coverted with #to_s and so will be allowed. It is not the job of
|
18
|
+
# this library to enforce legality, only to parse the PokéPaste format
|
19
|
+
[[:evs, Hash],
|
20
|
+
[:ivs, Hash],
|
21
|
+
[:level, Integer],
|
22
|
+
[:happiness, Integer],
|
23
|
+
[:moves, Array]].each do |attr, type|
|
24
|
+
unless attrs[attr].nil? || attrs[attr].is_a?(type)
|
25
|
+
raise TypeError, "expected type #{type} for :#{attr}, received #{attrs[attr].class}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless attrs[:shiny].nil? || [true, false].include?(attrs[:shiny])
|
30
|
+
raise TypeError, "expected (true|false|nil) for :shiny, received #{attrs[:shiny]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Process and set defaults for EVs and IVs
|
34
|
+
%i[evs ivs].each do |attr|
|
35
|
+
# Pluck the relevant value out of the attrs Hash if there is one
|
36
|
+
input_attr = attrs.delete(attr) || {}
|
37
|
+
|
38
|
+
# Error if this isn't a Hash
|
39
|
+
unless input_attr.is_a?(Hash)
|
40
|
+
raise ArgumentError, "expected a Hash for :#{attr}, received #{input_attr.class}"
|
41
|
+
end
|
42
|
+
|
43
|
+
stats = %i[hp atk def spa spd spe]
|
44
|
+
|
45
|
+
# Error if an invalid stat is specified
|
46
|
+
input_attr.each do |key, value|
|
47
|
+
unless stats.include?(key)
|
48
|
+
raise ArgumentError, "invalid :#{attr} key :#{key}, expected one of #{stats.keys}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set default for any stat that hasn't been specified
|
53
|
+
stats.each do |stat|
|
54
|
+
input_attr[stat] ||= attr == :evs ? 0 : 31
|
55
|
+
end
|
56
|
+
|
57
|
+
send "#{attr}=", input_attr
|
58
|
+
end
|
59
|
+
|
60
|
+
# Copy the attributes from the constructor to instance variables
|
61
|
+
attrs.each { |key, value| send "#{key}=", value }
|
62
|
+
|
63
|
+
# Both first letter and full word, string and symbol are supported for gender
|
64
|
+
if attrs[:gender]
|
65
|
+
gender = attrs[:gender].downcase.to_sym
|
66
|
+
if self.class.gender_abbrs.flatten.include?(gender)
|
67
|
+
# Either it's the key, or the value; this will find the value either way
|
68
|
+
@gender = self.class.gender_abbrs[gender] || gender
|
69
|
+
else
|
70
|
+
raise TypeError,
|
71
|
+
"expected nil or one of #{self.class.gender_abbrs.flatten} for :gender, received #{attrs[:gender]}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if attrs[:nature]
|
76
|
+
begin
|
77
|
+
@nature = attrs[:nature].is_a?(Integer) ? attrs[:nature] : attrs[:nature].downcase.to_sym
|
78
|
+
rescue NoMethodError
|
79
|
+
raise TypeError,
|
80
|
+
"expected a (String|Symbol|Integer) for :nature, received #{attrs[:nature].class}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
@shiny ||= false
|
85
|
+
@level ||= 50
|
86
|
+
@happiness ||= 255
|
87
|
+
@nature ||= :hardy
|
88
|
+
@moves ||= []
|
4
89
|
end
|
5
90
|
|
6
91
|
def to_s
|
92
|
+
# Build first line
|
93
|
+
str = @nickname ? "#{@nickname} (#{@species})" : @species.dup
|
94
|
+
str << " (#{@gender.to_s[0].upcase})" if @gender
|
95
|
+
str << " @ #{@item}" if @item
|
96
|
+
|
97
|
+
str << "\nAbility: #{@ability}" if @ability
|
98
|
+
str << "\nLevel: #{@level}" if @level != 50
|
99
|
+
str << "\nShiny: Yes" if @shiny
|
100
|
+
str << "\nTera Type: #{@tera_type.to_s.capitalize}" if @tera_type
|
101
|
+
str << "\nEVs: #{stat_string @evs, 0}" if @evs.any? { |_, value| value != 0 }
|
102
|
+
# Don't print neutral natures
|
103
|
+
unless %i[hardy docile serious bashful quirky].include? @nature
|
104
|
+
str << "\n#{@nature.to_s.capitalize} Nature"
|
105
|
+
end
|
106
|
+
str << "\nIVs: #{stat_string @ivs, 31}" if @ivs.any? { |_, value| value != 31 }
|
107
|
+
str << "\nHappiness: #{@happiness}" if @happiness != 255
|
108
|
+
|
109
|
+
@moves.each do |move|
|
110
|
+
str << "\n- #{move.is_a?(Array) ? move.join(" / ") : move}"
|
111
|
+
end
|
112
|
+
|
113
|
+
str
|
114
|
+
end
|
115
|
+
|
116
|
+
def shiny?
|
117
|
+
@shiny
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
@@stat_inflections = {
|
123
|
+
hp: "HP",
|
124
|
+
atk: "Atk",
|
125
|
+
def: "Def",
|
126
|
+
spa: "SpA",
|
127
|
+
spd: "SpD",
|
128
|
+
spe: "Spe"
|
129
|
+
}
|
130
|
+
|
131
|
+
def stat_string(stats, default)
|
132
|
+
stats.select { |_, value| value != default}
|
133
|
+
.map { |stat, value| "#{value} #{@@stat_inflections[stat]}" }.join(' / ')
|
7
134
|
end
|
8
135
|
end
|
9
136
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module PokePaste
|
2
4
|
class Team
|
3
5
|
include Enumerable
|
4
6
|
extend Forwardable
|
5
7
|
def_delegators :@team, *%i[size length [] empty? last index]
|
6
8
|
|
7
|
-
def initialize
|
9
|
+
def initialize
|
8
10
|
@team = []
|
9
11
|
end
|
10
12
|
|
@@ -13,6 +15,15 @@ module PokePaste
|
|
13
15
|
end
|
14
16
|
|
15
17
|
def to_s
|
18
|
+
map(&:to_s).join("\n\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
def <<(pkmn)
|
22
|
+
if pkmn.is_a? PokePaste::Pokemon
|
23
|
+
@team << pkmn
|
24
|
+
else
|
25
|
+
raise TypeError, "invalid type, PokePaste::Pokemon expected"
|
26
|
+
end
|
16
27
|
end
|
17
28
|
end
|
18
29
|
end
|
data/lib/pokepaste.rb
CHANGED
@@ -1,10 +1,112 @@
|
|
1
|
-
require "pokepaste/paste"
|
2
1
|
require "pokepaste/pokemon"
|
2
|
+
require "pokepaste/team"
|
3
|
+
|
4
|
+
require "open-uri"
|
3
5
|
|
4
6
|
module PokePaste
|
5
|
-
def parse(paste)
|
7
|
+
def self.parse(paste)
|
8
|
+
# Each paragraph is a Pokémon (separated by 1 or more blank lines)
|
9
|
+
paragraphs = paste.strip.split(/\n\s*\n/).map { |p| p.split("\n").map &:strip }
|
10
|
+
|
11
|
+
team = PokePaste::Team.new
|
12
|
+
|
13
|
+
paragraphs.each do |paragraph|
|
14
|
+
# Line 1 can contain species, nickname, gender, and item in format like:
|
15
|
+
# Bud (Bulbasaur) (M) @ Life Orb
|
16
|
+
# Only the species is required, however
|
17
|
+
line1 = paragraph.shift
|
18
|
+
before_at, item = line1.split /\s+@\s+/
|
19
|
+
|
20
|
+
# Now work from right to left, parsing off the parts in parens
|
21
|
+
|
22
|
+
# Set the gender to nil, :male, or :female
|
23
|
+
if gender = before_at.slice!(/\s*\((m(ale)?|f(emale)?)\)$/i)
|
24
|
+
# Get rid of the parens
|
25
|
+
[/^\s*\(/, /\)$/].each { |regex| gender.slice! regex }
|
26
|
+
gender = PokePaste::Pokemon.gender_abbrs[gender.downcase[0].to_sym]
|
27
|
+
end
|
28
|
+
|
29
|
+
# This regex requires a space between the nickname and opening paren
|
30
|
+
if species = before_at.slice!(/\s+\([^\)]+\)$/i)
|
31
|
+
# We found the species inside parens, which means a nickname is present
|
32
|
+
[/^\s*\(/, /\)$/].each { |regex| species.slice! regex }
|
33
|
+
nickname = before_at
|
34
|
+
else
|
35
|
+
# Otherwise all that remains is the species, and there is no nickname
|
36
|
+
species = before_at
|
37
|
+
nickname = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
pkmn = PokePaste::Pokemon.new species: species, nickname: nickname,
|
41
|
+
item: item, gender: gender
|
42
|
+
|
43
|
+
# Pull the moves out
|
44
|
+
pkmn.moves, paragraph = paragraph.partition { |line| line =~ /^\s*-/ }
|
45
|
+
if pkmn.moves.any?
|
46
|
+
pkmn.moves.map! do |line|
|
47
|
+
move_slot = line.sub /^\s*-\s*/, ""
|
48
|
+
move_slot.include?("/") ? move_slot.split(/\s*\/\s*/) : move_slot
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Pull the nature out. If there are multiple, the first is used
|
53
|
+
nature_line, paragraph = paragraph.partition { |line| line =~ /nature\s*$/i }
|
54
|
+
if nature_line.any?
|
55
|
+
pkmn.nature = nature_line.first.sub(/\s*nature\s*$/i, "").downcase.to_sym
|
56
|
+
end
|
57
|
+
|
58
|
+
# All that we're left with at this point are attributes that are denoted with
|
59
|
+
# the syntax "Attribute: Value". Let's loop over them and parse the attribute
|
60
|
+
paragraph.each do |line|
|
61
|
+
attribute, value = line.split /\s*:\s*/, 2
|
62
|
+
attribute = attribute.downcase.gsub(/\s+/, "_").to_sym
|
63
|
+
|
64
|
+
# At this point attribute will be a symbol with the snake_case approximation
|
65
|
+
# of whatever was before the first ":" in the string. If we know what it does,
|
66
|
+
# we can manipulate it as desired, otherwise just let it through as a string.
|
67
|
+
# This is intended to be a flexible format.
|
68
|
+
if %i[evs ivs].include?(attribute)
|
69
|
+
data = value.split /\s*\/\s*/
|
70
|
+
data.map { |d| d.split /\s+/, 2 }.each do |value, stat|
|
71
|
+
current_value = pkmn.send attribute
|
72
|
+
current_value[stat.downcase.to_sym] = value.to_i
|
73
|
+
pkmn.send "#{attribute}=", current_value
|
74
|
+
end
|
75
|
+
elsif %i[level happiness].include?(attribute)
|
76
|
+
pkmn.send "#{attribute}=", value.to_i
|
77
|
+
elsif attribute == :shiny
|
78
|
+
pkmn.shiny = %w[yes true].include?(value.downcase)
|
79
|
+
else
|
80
|
+
pkmn.send "#{attribute}=", value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
team << pkmn
|
85
|
+
end
|
86
|
+
|
87
|
+
team
|
6
88
|
end
|
7
89
|
|
8
|
-
def fetch(str)
|
90
|
+
def self.fetch(str)
|
91
|
+
input_url = URI.parse(str)
|
92
|
+
unless [nil, "pokepast.es"].include? input_url.host
|
93
|
+
raise ArgumentError, "invalid URL; must be valid pokepast.es URL or path, received '#{str}'"
|
94
|
+
end
|
95
|
+
|
96
|
+
path = (input_url.host ? input_url.path : str).gsub /^\//, ""
|
97
|
+
if path.empty?
|
98
|
+
raise ArgumentError, "invalid URL; no paste ID found in '#{str}'"
|
99
|
+
end
|
100
|
+
|
101
|
+
# The paste is in <article> tags
|
102
|
+
paste_content = URI.open("https://pokepast.es/#{path}").read.
|
103
|
+
slice(/(?<=\<article\>)[\S\s]*(?=\<\/article\>)/)
|
104
|
+
|
105
|
+
unless paste_content
|
106
|
+
raise OpenURI::HTTPError.new "no paste found at '#{str}'", 404
|
107
|
+
end
|
108
|
+
|
109
|
+
# Removing all HTML tags is sufficient to pass the string to the parser
|
110
|
+
parse paste_content.gsub(/\<\/?[^\>]+\>/, "")
|
9
111
|
end
|
10
112
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PokePaste do
|
4
|
+
let(:paste) { PokePaste::parse TEST_PASTE }
|
5
|
+
|
6
|
+
describe "#parse" do
|
7
|
+
TEST_DATA.each_with_index do |attrs, i|
|
8
|
+
attrs.each do |attr, value|
|
9
|
+
it "processes :#{attr}#{attr == :shiny ? '?' : ''} correctly" do
|
10
|
+
attr = (attr.to_s + "?").to_sym if attr == :shiny
|
11
|
+
expect(paste[i].send attr).to eq value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#fetch" do
|
18
|
+
before :each do
|
19
|
+
# stub a PokéPaste request
|
20
|
+
end
|
21
|
+
|
22
|
+
it "works with a full URL" do
|
23
|
+
fetch = PokePaste::fetch TEST_PASTE_URL
|
24
|
+
|
25
|
+
test_paste_equality paste, fetch
|
26
|
+
end
|
27
|
+
|
28
|
+
it "works with a path" do
|
29
|
+
fetch = PokePaste::fetch "/#{TEST_PASTE_ID}"
|
30
|
+
|
31
|
+
test_paste_equality paste, fetch
|
32
|
+
end
|
33
|
+
|
34
|
+
it "works with an ID" do
|
35
|
+
fetch = PokePaste::fetch TEST_PASTE_ID
|
36
|
+
|
37
|
+
test_paste_equality paste, fetch
|
38
|
+
end
|
39
|
+
|
40
|
+
it "fails with an invalid host or no path" do
|
41
|
+
["https://google.com/",
|
42
|
+
"https://pokepast.es",
|
43
|
+
"http://localhost/test"].each do |input|
|
44
|
+
expect { PokePaste::fetch input }.to raise_error ArgumentError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "fails with an invalid input" do
|
49
|
+
["https://pokepast.es/nobodyhome",
|
50
|
+
"somerandomtext",
|
51
|
+
"https://pokepast.es/syntax.html",
|
52
|
+
"syntax.html"].each do |input|
|
53
|
+
expect { PokePaste::fetch input }.to raise_error OpenURI::HTTPError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# For most of these the species doesn't matter, here's a shortcut
|
4
|
+
def init_pkmn(**args)
|
5
|
+
PokePaste::Pokemon.new species: "Bulbasaur", **args
|
6
|
+
end
|
7
|
+
|
8
|
+
GENDERS = {m: :male, f: :female}
|
9
|
+
|
10
|
+
describe PokePaste::Pokemon do
|
11
|
+
context "when initialized with no species" do
|
12
|
+
it "throws an ArgumentError" do
|
13
|
+
expect { PokePaste::Pokemon.new }.to raise_error ArgumentError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
%i[evs ivs shiny level happiness moves].each do |attr|
|
18
|
+
context "when initiaized with an invalid type for :#{attr}" do
|
19
|
+
it "throws a TypeError" do
|
20
|
+
expect { init_pkmn attr => "string" }.to raise_error TypeError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
GENDERS.each do |shorthand, gender|
|
26
|
+
context "when gender :#{shorthand} is used" do
|
27
|
+
it "expands it to :#{gender}" do
|
28
|
+
expect(init_pkmn(gender: shorthand).gender).to eq gender
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when a string '#{gender}' is used" do
|
33
|
+
it "changes it to a symbol" do
|
34
|
+
expect(init_pkmn(gender: gender.to_s).gender).to eq gender
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when a string '#{shorthand}' is used" do
|
39
|
+
it "changes it to the symbol :#{gender}" do
|
40
|
+
expect(init_pkmn(gender: shorthand.to_s).gender).to eq gender
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when a gender unavailable in the Pokémon games is used" do
|
46
|
+
it "raises a typeerror" do
|
47
|
+
expect { init_pkmn gender: :test }.to raise_error TypeError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "downcases the gender" do
|
52
|
+
expect(init_pkmn(gender: "Male").gender).to eq :male
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when you try to pass in a boolean for the nature" do
|
56
|
+
it "raises a typeerror" do
|
57
|
+
expect { init_pkmn nature: true }.to raise_error TypeError
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when you pass a string in for the nature" do
|
62
|
+
it "converts it to a lowercase symbol" do
|
63
|
+
expect(init_pkmn(nature: "Bold").nature).to eq :bold
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
%i[evs ivs].each do |attr|
|
68
|
+
# n is the default
|
69
|
+
n = attr == :evs ? 0 : 31
|
70
|
+
attr_title = attr.to_s.chop.upcase
|
71
|
+
|
72
|
+
context "when given a single #{attr_title}" do
|
73
|
+
it "keeps the rest of the #{attr_title}s at their defaults" do
|
74
|
+
expect(init_pkmn(attr => {hp: 10}).send attr).to eq({
|
75
|
+
hp: 10, atk: n, def: n, spa: n, spd: n, spe: n
|
76
|
+
})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when initialized with only a species" do
|
82
|
+
let(:pkmn) { PokePaste::Pokemon.new(species: "Armarouge") }
|
83
|
+
|
84
|
+
# The second 'mon in the test data is an Armarouge with
|
85
|
+
# all default values, nothing set except the species.
|
86
|
+
TEST_DATA[1].each do |attr, value|
|
87
|
+
it "sets the :#{attr} attribute correctly" do
|
88
|
+
expect(pkmn.send attr).to eq value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PokePaste::Team do
|
4
|
+
let :team do
|
5
|
+
team = PokePaste::Team.new
|
6
|
+
TEST_DATA.each { |pkmn| team << PokePaste::Pokemon.new(**pkmn) }
|
7
|
+
team
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#to_s" do
|
11
|
+
it "produces the correct PokéPaste" do
|
12
|
+
expect(team.to_s).to eq TEST_PASTE
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#<<" do
|
17
|
+
context "when given a PokePaste::Pokemon" do
|
18
|
+
it "adds it to the team" do
|
19
|
+
orig_size = team.size
|
20
|
+
team << PokePaste::Pokemon.new(species: (test_species = "Bulbasaur"))
|
21
|
+
|
22
|
+
expect(team.size).to eq (orig_size + 1)
|
23
|
+
expect(team.last.species).to eq test_species
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when given a string" do
|
28
|
+
it "throws a TypeError" do
|
29
|
+
expect { team << "string" }.to raise_error TypeError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
require "pokepaste"
|
2
|
+
|
1
3
|
# Include all files in spec/support
|
2
4
|
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
|
3
5
|
|
4
6
|
RSpec.configure do |config|
|
7
|
+
# Add `focus: true` hash parameter to a describe/context/it block
|
8
|
+
# to only run the specs in that block
|
9
|
+
config.filter_run_when_matching :focus
|
10
|
+
|
5
11
|
# Fuubar
|
6
12
|
config.add_formatter "Fuubar"
|
7
13
|
config.fuubar_progress_bar_options = { format: " %c/%C |%b>%i|%e " }
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# These aren't intended to be realistic or legal setups; this is merely to
|
2
|
+
# broadly test the features of the parser.
|
3
|
+
|
4
|
+
TEST_PASTE = <<~EOS.strip
|
5
|
+
Mr. Mime-Galar (M) @ Heavy-Duty Boots
|
6
|
+
Ability: Vital Spirit
|
7
|
+
Modest Nature
|
8
|
+
IVs: 0 Atk / 0 Spe
|
9
|
+
- Hidden Power [Dark]
|
10
|
+
- Freeze-Dry
|
11
|
+
- Dragon Hammer
|
12
|
+
- Acid
|
13
|
+
|
14
|
+
Armarouge
|
15
|
+
|
16
|
+
Manny (Great Tusk)
|
17
|
+
Ability: Protosynthesis
|
18
|
+
Level: 85
|
19
|
+
Shiny: Yes
|
20
|
+
Tera Type: Ground
|
21
|
+
EVs: 1 HP / 2 Atk / 3 Def / 4 SpA / 5 SpD / 6 Spe
|
22
|
+
Jolly Nature
|
23
|
+
IVs: 1 HP / 2 Atk / 3 Def / 4 SpA / 5 SpD / 6 Spe
|
24
|
+
Happiness: 100
|
25
|
+
- Headlong Rush
|
26
|
+
- Earthquake
|
27
|
+
|
28
|
+
Wo-Chien @ Rocky Helmet
|
29
|
+
Ability: Tablets of Ruin
|
30
|
+
Tera Type: Dark
|
31
|
+
- Ruination
|
32
|
+
- Zen Headbutt
|
33
|
+
|
34
|
+
Glimmora (F)
|
35
|
+
Shiny: Yes
|
36
|
+
EVs: 4 Atk / 252 SpA / 252 Spe
|
37
|
+
Naive Nature
|
38
|
+
IVs: 0 Atk
|
39
|
+
- Dazzling Gleam
|
40
|
+
- Flash Cannon
|
41
|
+
- Mortal Spin
|
42
|
+
- Power Gem / Protect
|
43
|
+
EOS
|
44
|
+
|
45
|
+
# Identical to TEST_PASTE, uploaded to pokepast.es:
|
46
|
+
TEST_PASTE_URL = "https://pokepast.es/a979ce56c2109382"
|
47
|
+
TEST_PASTE_ID = "a979ce56c2109382"
|
48
|
+
|
49
|
+
# This paste is expected to be parsed into this data:
|
50
|
+
TEST_DATA = [
|
51
|
+
{
|
52
|
+
species: "Mr. Mime-Galar",
|
53
|
+
nickname: nil,
|
54
|
+
gender: :male,
|
55
|
+
item: "Heavy-Duty Boots",
|
56
|
+
evs: {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0},
|
57
|
+
ivs: {hp: 31, atk: 0, def: 31, spa: 31, spd: 31, spe: 0},
|
58
|
+
shiny: false,
|
59
|
+
ability: "Vital Spirit",
|
60
|
+
tera_type: nil,
|
61
|
+
level: 50,
|
62
|
+
happiness: 255,
|
63
|
+
nature: :modest,
|
64
|
+
moves: ["Hidden Power [Dark]", "Freeze-Dry", "Dragon Hammer", "Acid"]
|
65
|
+
},
|
66
|
+
{
|
67
|
+
species: "Armarouge",
|
68
|
+
nickname: nil,
|
69
|
+
gender: nil,
|
70
|
+
item: nil,
|
71
|
+
evs: {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0},
|
72
|
+
ivs: {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31},
|
73
|
+
shiny: false,
|
74
|
+
ability: nil,
|
75
|
+
tera_type: nil,
|
76
|
+
level: 50,
|
77
|
+
happiness: 255,
|
78
|
+
nature: :hardy,
|
79
|
+
moves: []
|
80
|
+
},
|
81
|
+
{
|
82
|
+
species: "Great Tusk",
|
83
|
+
nickname: "Manny",
|
84
|
+
gender: nil,
|
85
|
+
item: nil,
|
86
|
+
evs: {hp: 1, atk: 2, def: 3, spa: 4, spd: 5, spe: 6},
|
87
|
+
ivs: {hp: 1, atk: 2, def: 3, spa: 4, spd: 5, spe: 6},
|
88
|
+
shiny: true,
|
89
|
+
ability: "Protosynthesis",
|
90
|
+
tera_type: "Ground",
|
91
|
+
level: 85,
|
92
|
+
happiness: 100,
|
93
|
+
nature: :jolly,
|
94
|
+
moves: ["Headlong Rush", "Earthquake"]
|
95
|
+
},
|
96
|
+
{
|
97
|
+
species: "Wo-Chien",
|
98
|
+
nickname: nil,
|
99
|
+
gender: nil,
|
100
|
+
item: "Rocky Helmet",
|
101
|
+
evs: {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0},
|
102
|
+
ivs: {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31},
|
103
|
+
shiny: false,
|
104
|
+
ability: "Tablets of Ruin",
|
105
|
+
tera_type: "Dark",
|
106
|
+
level: 50,
|
107
|
+
happiness: 255,
|
108
|
+
nature: :hardy,
|
109
|
+
moves: ["Ruination", "Zen Headbutt"]
|
110
|
+
},
|
111
|
+
{
|
112
|
+
species: "Glimmora",
|
113
|
+
nickname: nil,
|
114
|
+
gender: :female,
|
115
|
+
item: nil,
|
116
|
+
evs: {hp: 0, atk: 4, def: 0, spa: 252, spd: 0, spe: 252},
|
117
|
+
ivs: {hp: 31, atk: 0, def: 31, spa: 31, spd: 31, spe: 31},
|
118
|
+
shiny: true,
|
119
|
+
ability: nil,
|
120
|
+
tera_type: nil,
|
121
|
+
level: 50,
|
122
|
+
happiness: 255,
|
123
|
+
nature: :naive,
|
124
|
+
moves: ["Dazzling Gleam", "Flash Cannon", "Mortal Spin", ["Power Gem", "Protect"]]
|
125
|
+
}
|
126
|
+
]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pokepaste
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vinny Diehl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -77,10 +77,15 @@ files:
|
|
77
77
|
- Rakefile
|
78
78
|
- VERSION
|
79
79
|
- lib/pokepaste.rb
|
80
|
-
- lib/pokepaste/paste.rb
|
81
80
|
- lib/pokepaste/pokemon.rb
|
81
|
+
- lib/pokepaste/team.rb
|
82
82
|
- pokepaste.gemspec
|
83
|
+
- spec/pokepaste/parser_spec.rb
|
84
|
+
- spec/pokepaste/pokemon_spec.rb
|
85
|
+
- spec/pokepaste/team_spec.rb
|
83
86
|
- spec/spec_helper.rb
|
87
|
+
- spec/support/paste_equality.rb
|
88
|
+
- spec/support/test_paste.rb
|
84
89
|
homepage: https://github.com/vinnydiehl/pokepaste-ruby
|
85
90
|
licenses:
|
86
91
|
- MIT
|
@@ -105,4 +110,9 @@ signing_key:
|
|
105
110
|
specification_version: 4
|
106
111
|
summary: PokéPaste parser for Ruby
|
107
112
|
test_files:
|
113
|
+
- spec/pokepaste/parser_spec.rb
|
114
|
+
- spec/pokepaste/pokemon_spec.rb
|
115
|
+
- spec/pokepaste/team_spec.rb
|
108
116
|
- spec/spec_helper.rb
|
117
|
+
- spec/support/paste_equality.rb
|
118
|
+
- spec/support/test_paste.rb
|