ffxiv 0.9.1 → 0.9.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fb7ce29800d85a1d741dced5bb8ba1049b63115
4
- data.tar.gz: 40595334045f34238ec0e636e896fb24f521252f
3
+ metadata.gz: 20be78bbbb48a7d2a7dffb7eb33531c739d7dbbe
4
+ data.tar.gz: 9c3296043f94c90b6094eaf5ad680e02346f1d8b
5
5
  SHA512:
6
- metadata.gz: cdfe1416572fa6daf7a401c00d48a3d87720777b531585230f7d82a0c5e539f4984e8be5f365c8f599ab384a59261245a51132256a04022a7b051391242f8f23
7
- data.tar.gz: a5951abe15687d137cee233c7fd2fda8a224d73cc5d016caf7b5688e0baaeb91f1d1d9f3baaa4bdadde382b8f39d51f055321567cdac4ae861ed10454a8f1e22
6
+ metadata.gz: 5782cde3206205e06590e452dbb6a5baae3103758f8da63ea0cd318a46b58eee203e2dd3edf2b111a45a26c29a4c4e5465f0d14dfa5ebf412a2aa2a6ca5873d7
7
+ data.tar.gz: d7e2044a0c0626daa1f5a0a7f97dc7c785a0f074085b7a5612997ba7f093fc3ba426de6fb66fd4b2e902e01dcdec852bee1fb441c997502025e8bead6b3b8722
@@ -8,17 +8,37 @@ require "open-uri"
8
8
  require "lodestone/model"
9
9
  require "lodestone/character"
10
10
  require "lodestone/free-company"
11
+ require "lodestone/linkshell"
11
12
 
12
13
  module FFXIV
13
14
  module Lodestone
15
+
16
+ @@debug = false
17
+
14
18
  class << self
19
+
20
+ def debug
21
+ @@debug
22
+ end
23
+
24
+ def debug=(flag)
25
+ @@debug = flag
26
+ end
27
+
28
+ def d(str)
29
+ puts "\033[35m[Debug]\033[0m #{str}" if @@debug
30
+ end
31
+
15
32
  def fetch(endpoint)
16
33
  uri = "http://na.finalfantasyxiv.com/lodestone/" + endpoint
34
+ d("Fetching #{uri} ......")
17
35
  html, charset = open(uri) do |page|
18
36
  [page.read, page.charset]
19
37
  end
38
+ d(" done (size=#{html.size}, charset=#{charset})")
20
39
  Nokogiri::HTML.parse(html, nil, charset)
21
40
  end
41
+
22
42
  end
23
43
  end
24
44
  end
@@ -3,16 +3,50 @@ module FFXIV
3
3
  class Character < Model
4
4
 
5
5
  attr_accessor :id, :name, :server, :thumbnail_uri, :image_uri, :race, :subrace, :gender,
6
- :nameday, :guardian, :city_state, :grand_company, :grand_company_rank,
7
- :free_company, :minions, :mounts, :end_contents, :self_introduction, :classes,
8
- :num_blogs, :first_blogged, :latest_blogged, :bpd, :free_company_rank
6
+ :nameday, :guardian, :city_state, :grand_company, :grand_company_rank, :free_company,
7
+ :minions, :mounts, :end_contents, :eternal_bonding, :self_introduction, :classes,
8
+ :num_blogs, :first_blogged, :latest_blogged, :bpd, :free_company_rank, :linkshell_rank
9
9
  alias :end_contents? :end_contents
10
+ alias :eternal_bonding? :eternal_bonding
10
11
 
11
12
  class << self
12
13
 
14
+ def search(keyword, server: nil, page: 1, verbose: false)
15
+ dom = Lodestone.fetch("character/?q=#{URI.escape(keyword)}&worldname=#{server ? URI.escape(server) : ""}&page=#{URI.escape(page.to_s)}")
16
+ # Couldn't find a way to get this node with CSS...
17
+ characters = dom.xpath("//comment()[.=' result ']/following::table[1]/tr").map do |tr|
18
+ h4 = tr.at("td h4")
19
+ a = h4.at("a")
20
+ id = a.attr("href").split("/")[-1].to_i
21
+ if verbose
22
+ self.find_by_id(id)
23
+ else
24
+ self.new({
25
+ id: id,
26
+ name: a.content,
27
+ server: h4.at("span").content.strip[1...-1],
28
+ thumbnail_uri: drop_uts(tr.at("th img").attr("src"))
29
+ })
30
+ end
31
+ end
32
+ pagination = dom.at("div.current_list")
33
+ span_total = pagination.at("span.total")
34
+ raise "Character not found" unless span_total
35
+ total = span_total.content.to_i
36
+ results = {
37
+ show_start: pagination.at("span.show_start").content.to_i,
38
+ show_end: pagination.at("span.show_end").content.to_i,
39
+ total: total,
40
+ num_pages: (total / 50.0).ceil,
41
+ characters: characters
42
+ }
43
+ end
44
+
13
45
  def name_to_id(name, server)
14
- dom = Lodestone.fetch("character/?q=#{URI.escape(name)}&worldname=#{URI.escape(server)}")
15
- dom.at("h4.player_name_gold a").attr("href").split("/")[-1].to_i
46
+ self.search(name, server: server)[:characters].each do |ch|
47
+ return ch.id if name == ch.name
48
+ end
49
+ nil
16
50
  end
17
51
 
18
52
  def find_by_id(id)
@@ -21,36 +55,57 @@ module FFXIV
21
55
 
22
56
  props = {}
23
57
  props[:id] = id
24
- props[:name] = dom.css("div.player_name_txt h2 a").inner_text
25
- props[:server] = dom.css("div.player_name_txt h2 span").inner_text[2...-1]
26
- props[:thumbnail_uri] = drop_uts(dom.css("div.player_name_thumb img").attr("src").inner_text)
27
- props[:image_uri] = drop_uts(dom.css("img[width='264']").attr("src").inner_text)
28
- props[:race], props[:subrace], props[:gender] = dom.css("div.chara_profile_title").inner_text.strip.split(" / ")
29
- dom.css("ul.chara_profile_list li").to_a.each do |n|
30
- t = n.inner_text
31
- if t.include?("Nameday")
32
- props[:nameday], props[:guardian] = n.css(".txt_yellow").to_a.map(&:inner_text)
33
- elsif t.include?("City-state")
34
- props[:city_state] = n.css(".txt_yellow").inner_text
35
- elsif t.include?("Grand Company")
36
- props[:grand_company], props[:grand_company_rank] = n.css(".txt_yellow").inner_text.split("/")
37
- elsif t.include?("Free Company")
38
- props[:free_company] = n.css(".txt_yellow").inner_text
39
- end
58
+ ch_name = dom.at("div.player_name_txt h2 a")
59
+ props[:name] = ch_name.content
60
+ props[:server] = ch_name.next_element.content.strip[1...-1]
61
+ props[:thumbnail_uri] = drop_uts(dom.at("div.player_name_thumb img").attr("src"))
62
+ props[:image_uri] = drop_uts(dom.at("div.bg_chara_264 img").attr("src"))
63
+ props[:race], props[:subrace], gender = dom.at("div.chara_profile_title").content.strip.split(" / ")
64
+ props[:gender] = case gender
65
+ when "" then :female
66
+ when "♂" then :male
67
+ else raise "Unrecognized gender symbol: #{gender}"
40
68
  end
41
- dom.css("div.area_header_w358_inner").to_a.each do |n|
42
- aname = n.css("h4.ic_silver").inner_text.downcase
43
- items = n.css("a.ic_reflection_box").to_a.map{|m| m.attr("title")}.map{|i| i.capitalize.gsub(/[\s][a-z]/) {|s| s.upcase}}.sort
44
- props[:"#{aname}"] = items
69
+
70
+ dom.search("dl.chara_profile_box_info").each do |n|
71
+ n.search("dd.txt").each do |dd|
72
+ t = dd.next_element.content
73
+ case dd.content
74
+ when "Nameday"
75
+ props[:nameday] = t
76
+ when "Guardian"
77
+ props[:guardian] = t
78
+ when "City-state"
79
+ props[:city_state] = t
80
+ when "Grand Company"
81
+ props[:grand_company], props[:grand_company_rank] = t.split("/")
82
+ when "Free Company"
83
+ props[:free_company] = FreeCompany.new(name: t, server: props[:server])
84
+ end
85
+ end
45
86
  end
87
+
88
+ # The first "minion_box" contains mounts, and they need capitalization unlike minions.
89
+ minion_boxes = dom.search("div.minion_box")
90
+ props[:mounts] = minion_boxes[0].search("a").map{|a| a.attr("title").split.map(&:capitalize).join(' ')}
91
+ props[:minions] = minion_boxes[1].search("a").map{|a| a.attr("title")}
92
+
93
+ # Let's assume that whoever has this mount has slained Ultima Weapon and watched the ending movie, hence is qualified for the endgame contents.
46
94
  props[:end_contents] = props[:mounts].include?("Magitek Armor")
47
- props[:self_introduction] = dom.css("div.txt_selfintroduction").inner_html.strip
95
+
96
+ # Likewise, assume that whoever has this mount has purchased Gold or Platinum eternal bonding.
97
+ # Note that Standard version doesn't come with the mount, so use nil instead of false to indicate "unknown".
98
+ props[:eternal_bonding] = props[:mounts].include?("Ceremony Chocobo") ? true : nil
99
+
100
+ self_introduction = dom.at("div.txt_selfintroduction").inner_html.strip
101
+ props[:self_introduction] = self_introduction == "" ? nil : self_introduction
102
+
48
103
  props[:classes] = {}
49
104
  %w{fighter sorcerer crafter gatherer}.each do |discipline|
50
- dom.css("h4.class_#{discipline} + div.table_black_w626 td.ic_class_wh24_box").to_a.each do |td|
51
- txt = td.inner_text
52
- if !txt.empty?
53
- lvl = td.next_sibling().next_sibling().inner_text.to_i
105
+ dom.search("h4.class_#{discipline} + div.table_black_w626 td.ic_class_wh24_box").each do |td|
106
+ txt = td.content
107
+ unless txt.empty?
108
+ lvl = td.next_sibling().next_sibling().content.to_i
54
109
  props[:classes][txt] = lvl == 0 ? nil : lvl
55
110
  end
56
111
  end
@@ -65,6 +120,13 @@ module FFXIV
65
120
 
66
121
  end
67
122
 
123
+ def free_company(fetch = false)
124
+ if fetch
125
+ @free_company = FreeCompany.find_by_name(@free_company, @server)
126
+ end
127
+ @free_company
128
+ end
129
+
68
130
  def num_blogs
69
131
  init_blog; @num_blogs
70
132
  end
@@ -81,6 +143,77 @@ module FFXIV
81
143
  init_blog; @first_blogged
82
144
  end
83
145
 
146
+ def blogs(load_details = false)
147
+ unless @blogs
148
+ @blogs = []
149
+ if num_blogs > 0
150
+ num_blog_pages = (num_blogs / 10.0).ceil
151
+ 1.upto(num_blog_pages) do |page|
152
+ dom = Lodestone.fetch("character/#{@id}/blog?order=2&page=#{page}")
153
+ dom.search("section.base_body").each do |section_blog|
154
+ a_title = section_blog.at("a.blog_title")
155
+ blog = {
156
+ id: a_title.attr("href").split("/")[-1],
157
+ title: a_title.content,
158
+ date: Time.at(section_blog.at("script").content[/ldst_strftime\((\d{10}),/, 1].to_i),
159
+ num_comments: section_blog.at("span.ic_comment").content.to_i
160
+ }
161
+ if load_details
162
+ dom_blog = Lodestone.fetch("character/#{@id}/blog/#{blog[:id]}")
163
+ blog[:body] = dom_blog.at(".txt_selfintroduction").inner_html.strip
164
+
165
+ blog[:comments] = []
166
+ if blog[:num_comments] > 0
167
+ dom_blog.search("div.comment").each do |dom_comment|
168
+ unless dom_comment.at("div.comment_delete_box")
169
+ div_by = dom_comment.at("div.player_id")
170
+ by = nil
171
+ if div_by
172
+ a_by = div_by.at("a")
173
+ by = self.class.new({
174
+ id: a_by.attr("href").split("/")[-1],
175
+ name: a_by.content,
176
+ server: div_by.at("span").content.strip[1...-1]
177
+ })
178
+ end
179
+ blog[:comments] << {
180
+ by: by,
181
+ date: Time.at(dom_comment.at("script").content[/ldst_strftime\((\d{10}),/, 1].to_i),
182
+ body: dom_comment.at("div.balloon_body_inner").inner_html.strip
183
+ }
184
+ end
185
+ end
186
+ end
187
+
188
+ blog[:tags] = []
189
+ a_tags = dom_blog.search("div.diary_tag a")
190
+ if a_tags
191
+ a_tags.each do |a_tag|
192
+ blog[:tags] << a_tag.content[1...-1]
193
+ end
194
+ end
195
+
196
+ blog[:images] = []
197
+ img_thumbs = dom_blog.search("ul.thumb_list li img")
198
+ if img_thumbs
199
+ img_thumbs.each do |img_thumb|
200
+ unless img_thumb.attr("class") == "img_delete"
201
+ blog[:images] << {
202
+ thumbnail: img_thumb.attr("src"),
203
+ original: img_thumb.attr("data-origin_src")
204
+ }
205
+ end
206
+ end
207
+ end
208
+ end
209
+ @blogs << blog
210
+ end
211
+ end
212
+ end
213
+ end
214
+ @blogs
215
+ end
216
+
84
217
  def thumbnail_uri
85
218
  @thumbnail_uri + "?#{Time.now.to_i}"
86
219
  end
@@ -94,11 +227,11 @@ module FFXIV
94
227
  if @num_blogs.nil?
95
228
  dom1 = Lodestone.fetch("character/#{@id}/blog?order=1")
96
229
  total_node = dom1.at("div.current_list span.total")
97
- @num_blogs = total_node.nil? ? 0 : total_node.inner_text.to_i
230
+ @num_blogs = total_node.nil? ? 0 : total_node.content.to_i
98
231
  if @num_blogs > 0
99
232
  dom2 = Lodestone.fetch("character/#{@id}/blog?order=2")
100
233
  {latest_blogged: dom1, first_blogged: dom2}.each do |prop, dom|
101
- txt = dom.at("h3.header_title").inner_text
234
+ txt = dom.at("h3.header_title").content
102
235
  uts = txt.match(/ldst_strftime\((\d{10}), 'YMDHM'\)/)[1].to_i
103
236
  send("#{prop}=", Time.at(uts).utc)
104
237
  end
@@ -9,11 +9,46 @@ module FFXIV
9
9
 
10
10
  class << self
11
11
 
12
+ def search(keyword, server: nil, page: 1, verbose: false)
13
+ dom = Lodestone.fetch("freecompany/?q=#{URI.escape(keyword)}&worldname=#{URI.escape(server)}&page=#{URI.escape(page.to_s)}")
14
+ free_companies = dom.search("table.table_elements_com_fc tr").map do |tr|
15
+ h4 = tr.at("td h4")
16
+ a = h4.at("a")
17
+ id = a.attr("href").split("/")[-1].to_i
18
+ if verbose
19
+ self.find_by_id(id)
20
+ else
21
+ self.new({
22
+ id: id,
23
+ name: a.content,
24
+ server: h4.at("span").content.strip[1...-1],
25
+ grand_company: tr.at("div.groundcompany_name").content
26
+ })
27
+ end
28
+ end
29
+ pagination = dom.at("div.current_list")
30
+ total = pagination.at("span.total").content.to_i
31
+ results = {
32
+ show_start: pagination.at("span.show_start").content.to_i,
33
+ show_end: pagination.at("span.show_end").content.to_i,
34
+ total: total,
35
+ num_pages: (total / 50.0).ceil,
36
+ free_companies: free_companies
37
+ }
38
+ end
39
+
12
40
  def name_to_id(name, server)
13
41
  dom = Lodestone.fetch("freecompany/?q=#{URI.escape(name)}&worldname=#{URI.escape(server)}")
14
42
  dom.at("div.ic_freecompany_box a").attr("href").split("/")[-1].to_i
15
43
  end
16
44
 
45
+ def name_to_id(name, server)
46
+ self.search(name, server: server)[:free_companies].each do |fc|
47
+ return fc.id if name == fc.name
48
+ end
49
+ nil
50
+ end
51
+
17
52
  def find_by_id(id)
18
53
  begin
19
54
  dom = Lodestone.fetch("freecompany/#{id}")
@@ -21,7 +56,7 @@ module FFXIV
21
56
  props = {}
22
57
  props[:id] = id
23
58
 
24
- props[:logo_uri] = dom.css("div.ic_crest_64 img").to_a.map{|n| n.attr("src")}
59
+ props[:logo_uri] = dom.search("div.ic_crest_64 img").map{|n| n.attr("src")}
25
60
 
26
61
  gcs_node = dom.at("span.friendship_color")
27
62
  props[:grand_company_standing] = gcs_node.inner_text[1...-1]
@@ -37,7 +72,7 @@ module FFXIV
37
72
 
38
73
  props[:tag] = dom.at("td.vm").last_element_child.next_sibling.inner_text[1...-1]
39
74
 
40
- dom.css("table.table_style2 tr").to_a.each do |tr|
75
+ dom.search("table.table_style2 tr").each do |tr|
41
76
  td_node = tr.at("td")
42
77
  td_text = td_node.inner_text.strip
43
78
  case tr.at("th").inner_text
@@ -52,25 +87,25 @@ module FFXIV
52
87
  props[:weekly_rank] = weekly.include?("--") ? nil : weekly.match(/\d+/)[0].to_i
53
88
  props[:monthly_rank] = monthly.include?("--") ? nil : monthly.match(/\d+/)[0].to_i
54
89
  when "Company Slogan"
55
- props[:slogan] = td_text
90
+ props[:slogan] = td_text == "" ? nil : td_text
56
91
  when "Active"
57
- props[:active] = td_text
92
+ props[:active] = td_text == "Not specified" ? nil : td_text
58
93
  when "Recruitment"
59
94
  props[:recruiting] = td_text == "Open"
60
95
  when "Focus"
61
- props[:focus] = td_node.css("img").to_a.map{|n| n.attr("title")}
96
+ props[:focus] = td_node.search("li:not(.icon_off) img").map{|n| n.attr("title")}
62
97
  when "Seeking"
63
- props[:seeking] = td_node.css("img").to_a.map{|n| n.attr("title")}
98
+ props[:seeking] = td_node.search("li:not(.icon_off) img").map{|n| n.attr("title")}
64
99
  when "Estate Profile"
65
100
  name_node = td_node.at("div.txt_yellow")
66
101
  if name_node
67
- address_size, greeting = td_node.css("p").to_a.map(&:inner_text)
102
+ address_size, greeting = td_node.search("p").map(&:inner_text)
68
103
  address, size = address_size.split(" (")
69
104
  props[:housing] = {
70
105
  name: name_node.inner_text,
71
106
  address: address,
72
107
  size: size[0...-1],
73
- greeting: greeting
108
+ greeting: greeting == "No greeting available." ? nil : greeting
74
109
  }
75
110
  else
76
111
  props[:housing] = nil
@@ -91,15 +126,15 @@ module FFXIV
91
126
  num_pages = (@num_members / 50.0).ceil # 50 members / page
92
127
  1.upto(num_pages) do |page_no|
93
128
  dom = Lodestone.fetch("freecompany/#{@id}/member/?page=#{page_no}")
94
- dom.css("div.player_name_area").to_a.each do |node|
129
+ dom.search("div.player_name_area").each do |node|
95
130
  cid = node.at("div.name_box a").attr("href").split("/")[-1]
96
- fcrank = node.at("div.fc_member_status").inner_text
131
+ fcrank = node.at("div.fc_member_status").content.strip
97
132
  members[cid] = fcrank
98
133
  end
99
134
  end
100
135
  characters = []
101
136
  members.each do |cid, fcrank|
102
- character = Character.find(cid)
137
+ character = Character.find_by_id(cid)
103
138
  character.free_company_rank = fcrank.strip
104
139
  characters << character
105
140
  end
@@ -0,0 +1,92 @@
1
+ module FFXIV
2
+ module Lodestone
3
+ class Linkshell < Model
4
+
5
+ attr_accessor :id, :name, :server, :members, :num_members
6
+
7
+ class << self
8
+
9
+ def search(keyword, server: nil, page: 1, verbose: false)
10
+ dom = Lodestone.fetch("linkshell/?q=#{URI.escape(keyword)}&worldname=#{URI.escape(server)}&page=#{URI.escape(page.to_s)}")
11
+ linkshells = dom.search("table.table_elements_com_ls tr").map do |tr|
12
+ h4 = tr.at("th h4")
13
+ a = h4.at("a")
14
+ id = a.attr("href").split("/")[-1].to_i
15
+ if verbose
16
+ self.find_by_id(id)
17
+ else
18
+ self.new({
19
+ id: id,
20
+ name: a.content,
21
+ server: h4.at("span").content.strip[1...-1],
22
+ num_members: tr.at("td span").content.split(": ")[1].to_i
23
+ })
24
+ end
25
+ end
26
+ pagination = dom.at("div.current_list")
27
+ total = pagination.at("span.total").content.to_i
28
+ results = {
29
+ show_start: pagination.at("span.show_start").content.to_i,
30
+ show_end: pagination.at("span.show_end").content.to_i,
31
+ total: total,
32
+ num_pages: (total / 50.0).ceil,
33
+ linkshells: linkshells
34
+ }
35
+ end
36
+
37
+ def name_to_id(name, server)
38
+ self.search(name, server: server)[:linkshells].each do |ls|
39
+ return ls.id if name == ls.name
40
+ end
41
+ nil
42
+ end
43
+
44
+ def find_by_id(id)
45
+ begin
46
+ dom = Lodestone.fetch("linkshell/#{id}")
47
+ props = {}
48
+ props[:id] = id
49
+ buff = dom.at("div.contents_header h2").content.match(/^(.+)\s\((.+)\)$/)
50
+ props[:name] = buff[1]
51
+ props[:server] = buff[2]
52
+ props[:num_members] = dom.at("h3.ic_silver").content.match(/\s\((\d+)\s/)[1].to_i
53
+ self.new(props)
54
+ rescue => e
55
+ pp e
56
+ nil
57
+ end
58
+ end
59
+ end
60
+
61
+ def members
62
+ if @members.nil?
63
+ members = {}
64
+ num_pages = (@num_members / 50.0).ceil # 50 members / page
65
+ 1.upto(num_pages) do |page_no|
66
+ dom = Lodestone.fetch("linkshell/#{@id}?page=#{page_no}")
67
+ dom.search("div.player_name_area").each do |node|
68
+ cid = node.at("div.name_box a").attr("href").split("/")[-1]
69
+ if node.at("span.ic_master")
70
+ lsrank = :master
71
+ elsif node.at("span.ic_leader")
72
+ lsrank = :leader
73
+ else
74
+ lsrank = :member
75
+ end
76
+ members[cid] = lsrank
77
+ end
78
+ end
79
+ characters = []
80
+ members.each do |cid, lsrank|
81
+ character = Character.find_by_id(cid)
82
+ character.linkshell_rank = lsrank
83
+ characters << character
84
+ end
85
+ @members = characters
86
+ end
87
+ @members
88
+ end
89
+
90
+ end
91
+ end
92
+ end
metadata CHANGED
@@ -1,18 +1,39 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffxiv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
- - Isjaki Kveikur
7
+ - Syro Bonkus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-29 00:00:00.000000000 Z
12
- dependencies: []
13
- description: An unofficial FFXIV ARR toolkit for Ruby, featuring Lodestone scraper.
11
+ date: 2015-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 1.7.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.5.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 1.7.0
33
+ description: An unofficial Final Fantasy XIV / A Realm Reborn toolkit for Ruby, featuring
34
+ Lodestone scraper.
14
35
  email:
15
- - isjaki.xiv@gmail.com
36
+ - sb.ffxiv@gmail.com
16
37
  executables: []
17
38
  extensions: []
18
39
  extra_rdoc_files: []
@@ -21,6 +42,7 @@ files:
21
42
  - lib/ffxiv/lodestone.rb
22
43
  - lib/ffxiv/lodestone/character.rb
23
44
  - lib/ffxiv/lodestone/free-company.rb
45
+ - lib/ffxiv/lodestone/linkshell.rb
24
46
  - lib/ffxiv/lodestone/model.rb
25
47
  homepage: https://github.com/ffxiv/ffxiv
26
48
  licenses:
@@ -42,8 +64,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
64
  version: '0'
43
65
  requirements: []
44
66
  rubyforge_project:
45
- rubygems_version: 2.2.2
67
+ rubygems_version: 2.4.5
46
68
  signing_key:
47
69
  specification_version: 4
48
70
  summary: An unofficial FFXIV ARR toolkit for Ruby, featuring Lodestone scraper.
49
71
  test_files: []
72
+ has_rdoc: