pokepaste 0.0 → 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|