ann_wrapper 1.1.4 → 1.1.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: 1e57e389662bc751a163ecff82d950d89a79ff80
4
- data.tar.gz: 4916dd0335181b68cef44b1ae9b75f98c2eef270
3
+ metadata.gz: 3a9e7afef7ed3479ae7b65cd78990ac4ec590094
4
+ data.tar.gz: 9ac1f2658558da468d3c3bd36aa83827d989baf8
5
5
  SHA512:
6
- metadata.gz: 1358df5bfe4a4e892cbea93af1db570b11e31c30a3b2cd31cc99664b151945470eedcef7e88caf6607cb1e2cf4a66b980d8cbb382e8c1787d36fc0f0d0267353
7
- data.tar.gz: 666e68b082a5c2f555497b08820769a06f8b2dfe78f2fca695ba9c27d7652467d74bc5a5b10d77bf44c4b632a59bea52af02feb9c9626e5222b7a09dc98bdf68
6
+ metadata.gz: 033dc1f439ea2110322bd23366a51377fb550e691ea4f1adf00e327b0d2b26db677029dc37d1813fe621e908bb33747fc8a08203126d42d048e67c50cb72be61
7
+ data.tar.gz: 12606ade1ae66a7a131fb80eff2eeaab8f7ea90a4eeb7dccb5fafcc2f7981e222a160e458d89d620cb6effaba2bdfcdfba5da3c712ec6cb350310541c3c72ab7
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.2"
4
3
  - "1.9.3"
5
4
  - "2.0.0"
5
+ - "2.1.5"
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ # coveralls test coverage
4
+ gem 'coveralls', require: false
5
+
3
6
  # Specify your gem's dependencies in ann_wrapper.gemspec
4
7
  gemspec
data/README.md CHANGED
@@ -4,8 +4,8 @@
4
4
  [![Gem Version](https://badge.fury.io/rb/ann_wrapper.png)](http://badge.fury.io/rb/ann_wrapper)
5
5
  [![Build Status](https://travis-ci.org/Getkura/ann_wrapper.png?branch=dev)](https://travis-ci.org/Getkura/ann_wrapper)
6
6
  [![Dependency Status](https://gemnasium.com/Getkura/ann_wrapper.png)](https://gemnasium.com/Getkura/ann_wrapper)
7
- [![Code Climate](https://codeclimate.com/github/Getkura/ann_wrapper.png)](https://codeclimate.com/github/Getkura/ann_wrapper)
8
-
7
+ [![Code Climate](https://codeclimate.com/github/Getkura/ann_wrapper/badges/gpa.svg)](https://codeclimate.com/github/Getkura/ann_wrapper)
8
+ [![Coverage Status](https://coveralls.io/repos/Getkura/ann_wrapper/badge.png?branch=dev)](https://coveralls.io/r/Getkura/ann_wrapper?branch=dev)
9
9
 
10
10
  A simple ruby wrapper/abstraction for the [Anime News Network API](http://www.animenewsnetwork.com/encyclopedia/api.php)
11
11
 
@@ -25,82 +25,132 @@ Or install it yourself as:
25
25
 
26
26
  ## Usage
27
27
 
28
- Fetch an anime:
28
+ ###Fetch an anime:
29
+
30
+ anime = ANN_Wrapper.fetch_anime "id"
31
+ anime.title
32
+ anime.alt_titles
33
+ anime.synopsis
34
+ anime.num_episodes
35
+ anime.genres
36
+ anime.themes
37
+ anime.vintage
38
+ anime.op_theme
39
+ anime.ed_theme
40
+ anime.id
41
+ anime.type
42
+ anime.ratings
43
+ anime.episodes
44
+ anime.staff
45
+ anime.cast
46
+ anime.images
47
+ anime.to_h
48
+
49
+ ####Example:
29
50
 
30
51
  steins_gate = ANN_Wrapper.fetch_anime 11770
31
52
 
32
- Info:
33
-
53
+ #####Info:
54
+
34
55
  steins_gate.id
35
56
  => "11770"
36
-
57
+
37
58
  steins_gate.title
38
59
  => ["Steins;Gate"]
39
-
60
+
40
61
  steins_gate.alt_titles
41
62
  => {"PT"=>["Steins-Gate e a Teoria do Caos"], "JA"=>["シュタインズ・ゲート"], "ZH-TW"=>["命運石之門"], "KO"=>["슈타인즈 게이트"]}
42
63
 
43
64
  steins_gate.synopsis
44
65
  => ["Rintaro Okabe is a self-proclaimed "mad scientist" ... "]
45
-
66
+
46
67
  steins_gate.num_episodes
47
68
  => ["24"]
48
-
69
+
49
70
  steins_gate.vintage
50
71
  => ["2011-04-03 (Advanced screening)", "2011-04-05 to 2011-09-13"]
51
-
72
+
52
73
  steins_gate.genres
53
74
  => ["adventure", "comedy", "drama", "mystery", "psychological", "romance", "science fiction", "thriller"]
54
-
75
+
55
76
  steins_gate.themes
56
77
  => ["butterfly effect", "conspiracy", "technology", "Time travel"]
57
-
78
+
58
79
  steins_gate.op_theme
59
80
  => ["\"Hacking to the Gate\" by Kanako Ito"]
60
-
81
+
61
82
  steins_gate.ed_theme
62
83
  => ["\"Tokitsukasadoru Jūni no Meiyaku\" (刻司ル十二ノ盟約) by Yui Sakakibara", "#2: \"Sukai Kuraddo no Kansokusha\" (スカイクラッドの観測者) by Kanako Ito (ep 23)", "#3: \"Another Heaven\" by Kanako Itou (ep 24)"]
63
84
 
64
85
 
65
- Cast and Staff:
66
-
86
+ #####Cast and Staff:
87
+
67
88
  steins_gate.cast.find_all {|c| c.name.include? "Hanazawa"}
68
89
  => [#<struct ANN_Cast id="53741", role="Mayuri Shiina", name="Kana Hanazawa", lang="JA">]
69
-
90
+
70
91
  steins_gate.staff.find_all {|s| s.task.eql? "Director"}
71
92
  => [
72
- #<struct ANN_Staff id="593", task="Director", name="Takuya Satō">,
73
- #<struct ANN_Staff id="9693", task="Director", name="Hiroshi Hamasaki">,
93
+ #<struct ANN_Staff id="593", task="Director", name="Takuya Satō">,
94
+ #<struct ANN_Staff id="9693", task="Director", name="Hiroshi Hamasaki">,
74
95
  #<struct ANN_Staff id="35713", task="Director", name="Tomoki Kobayashi">
75
96
  ]
76
97
 
77
98
 
78
- Episodes:
99
+ #####Episodes:
79
100
 
80
101
  steins_gate.episodes.find_all {|e| e.title.include? "Prologue"}
81
102
  => [
82
- #<struct ANN_Episode number="1", title="Prologue of the Beginning and End", lang="EN">,
103
+ #<struct ANN_Episode number="1", title="Prologue of the Beginning and End", lang="EN">,
83
104
  #<struct ANN_Episode number="24", title="The Prologue Begins With the End", lang="EN">
84
105
  ]
85
-
106
+
86
107
  steins_gate.episodes.first.to_h
87
108
  => {:number=>"1", :title=>"Prologue of the Beginning and End", :lang=>"EN"}
88
-
89
- Images:
109
+
110
+ #####Images:
90
111
 
91
112
  steins_gate.images
92
113
  => [
93
- #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/fit200x200/encyc/A11770-1864351140.1370764886.jpg", width="200", height="125">,
94
- #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/max500x600/encyc/A11770-1864351140.1370764886.jpg", width="500", height="312">,
95
- #<struct ANN_Image src="http://cdn.animenewsnetwork.com/images/encyc/A11770-1864351140.1370764886.jpg", width="900", height="562">,
96
- #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/fit200x200/encyc/A11770-8.jpg", width="200", height="200">,
114
+ #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/fit200x200/encyc/A11770-1864351140.1370764886.jpg", width="200", height="125">,
115
+ #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/max500x600/encyc/A11770-1864351140.1370764886.jpg", width="500", height="312">,
116
+ #<struct ANN_Image src="http://cdn.animenewsnetwork.com/images/encyc/A11770-1864351140.1370764886.jpg", width="900", height="562">,
117
+ #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/fit200x200/encyc/A11770-8.jpg", width="200", height="200">,
97
118
  #<struct ANN_Image src="http://cdn.animenewsnetwork.com/thumbnails/max500x600/encyc/A11770-8.jpg", width="317", height="317">
98
119
  ]
120
+
121
+ #####Ratings:
99
122
 
100
-
101
-
102
-
103
-
123
+ steings_gate.ratings
124
+ => [
125
+ #<struct ANN_Rating votes="3788", weighted="9.1129", bayesian_score="9.1075">
126
+ ]
127
+
128
+ ###Fetch a manga:
129
+
130
+ Fetching a manga works exactly the same as an anime, but you should call the `fetch_manga` method.
131
+
132
+ manga = ANN_Wrapper.fetch_manga "id"
133
+ manga.title
134
+ manga.alt_titles
135
+ manga.synopsis
136
+ manga.genres
137
+ manga.vintage
138
+ manga.themes
139
+ manga.num_tankoubon
140
+ manga.num_pages
141
+ manga.id
142
+ manga.type
143
+ manga.staff
144
+ manga.ratings
145
+ manga.images
146
+ manga.to_h
147
+
148
+ ###Batching:
149
+ Send any number of ids in an array for a batch request.
150
+ This will return an array of ANN_Anime or ANN_Manga objects.
151
+
152
+ anime = ANN_Wrapper.batch_anime(["id_1", "id_2", "id_3", ...])
153
+ manga = ANN_Wrapper.batch_manga(["id_1", "id_2", "id_3", ...])
104
154
 
105
155
  ## Contributing
106
156
 
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["getkura+ann_wrapper@gmail.com"]
11
11
  spec.description = 'A simple wrapper for the Anime News Network API'
12
12
  spec.summary = 'Anime News Network API wrapper'
13
- spec.homepage = "http://documentup.com/Getkura/ann_wrapper"
13
+ spec.homepage = "http://getkura.github.io/ann_wrapper/"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -4,35 +4,59 @@
4
4
 
5
5
  require "net/http"
6
6
  require "nokogiri"
7
- require 'ann_wrapper/ann_objects'
7
+ require 'ann_wrapper/ann_anime'
8
+ require 'ann_wrapper/ann_manga'
9
+ require 'ann_wrapper/ann_report'
8
10
 
9
11
  # wrapper class for ANN API
10
12
  module ANN_Wrapper
11
13
  extend ANN_Wrapper
12
14
 
15
+ @@type = "anime"
16
+
13
17
  # ANN API anime url
14
18
  ANN_URL = "http://cdn.animenewsnetwork.com/encyclopedia"
15
19
  ANN_API_URL = "#{ANN_URL}/api.xml"
16
20
  ANN_REPORTS_URL = "#{ANN_URL}/reports.xml"
17
21
 
18
- # fetch anime and convert to ANN_Anime
19
- def fetch_anime(id, api_url=ANN_API_URL)
22
+ # fetch up to 50 items(Animes or Mangas) in one request
23
+ def batch_items(ids, api_url=ANN_API_URL)
20
24
  # append id to API url and send request
21
- url = "#{api_url}?anime=#{id.to_s}"
25
+ url = "#{api_url}?title=#{ids.first.to_s}"
26
+ ids[1..-1].each do |id|
27
+ url << "/#{id.to_s}"
28
+ end
22
29
 
23
30
  ann = fetch(url)
24
31
 
25
- return ann if ann.is_a?(ANN_Error)
32
+ return [ann] if ann.is_a?(ANN_Error)
33
+
34
+ all_items = ann.xpath("//ann/#{@@type}")
35
+ warnings = ann.xpath('//ann/warning')
36
+
37
+ return [ANN_Error.new(get_xml_error(ann))] if all_items.empty? and warnings.empty?
38
+
39
+ all_items = all_items.map { |item| Object.const_get("ANN_#{@@type.capitalize}").new(item) }
40
+ warnings = warnings.map { |warning| ANN_Error.new(get_xml_error(warning)) }
26
41
 
27
- anime = ann.at_xpath('//ann/anime')
42
+ all_items.push(*warnings)
43
+ end
28
44
 
29
- # initialize new ann_anime or error with ann object
30
- anime.nil? ? ANN_Error.new(get_xml_error(ann)) : ANN_Anime.new(anime)
45
+ # fetch anime and convert to ANN_Anime
46
+ def fetch_item(id, api_url=ANN_API_URL)
47
+ batch_items([id], api_url).first
31
48
  end
32
49
 
33
50
  # fetch list of titles via reports
34
- def fetch_titles(type="anime", nskip=0, nlist=50, name="", api_url=ANN_REPORTS_URL)
35
- url = "#{api_url}?id=155&type=#{type}&nskip=#{nskip}&nlist=#{nlist}"
51
+ def fetch_titles(options = {})
52
+ options[:type] ||= "anime"
53
+ options[:nskip] ||= 0
54
+ options[:nlist] ||= 50
55
+ options[:name] ||= ""
56
+ options[:api_url] ||= ANN_REPORTS_URL
57
+
58
+ url = "#{options[:api_url]}?id=155&type=#{options[:type]}&name=#{options[:name]}&nskip=#{options[:nskip]}&nlist=#{options[:nlist]}"
59
+
36
60
  report = fetch(url)
37
61
 
38
62
  return report if report.is_a?(ANN_Error)
@@ -44,6 +68,15 @@ extend ANN_Wrapper
44
68
  reports.map { |item| ANN_Report.new(item) }
45
69
  end
46
70
 
71
+ def method_missing(meth, *args, &block)
72
+ if meth.to_s =~ /^(fetch|batch)_(anime|manga)$/
73
+ @@type = $2
74
+ $1 == 'fetch' ? fetch_item(*args) : batch_items(*args)
75
+ else
76
+ super
77
+ end
78
+ end
79
+
47
80
  private
48
81
  # fetch data from ANN API via http GET request
49
82
  # returns Nokogiri or ANN_Error
@@ -55,16 +88,16 @@ extend ANN_Wrapper
55
88
  # get the response body and try converting to Nokogiri object
56
89
  Nokogiri.XML(resp.body)
57
90
  rescue
58
- ANN_Error.new("xml format error, API likely unavailable")
91
+ ANN_Error.new("Could not reach valid URL")
59
92
  end
60
- end
93
+ end
61
94
 
62
95
  # attempt to grab error message from XMLObject
63
96
  def get_xml_error(xobj)
64
97
  begin
65
98
  xobj.at_xpath('//ann/warning').content
66
- rescue NameError
67
- "bad response"
99
+ rescue NoMethodError
100
+ "unrecognized response body"
68
101
  end
69
102
  end
70
103
  end
@@ -0,0 +1,44 @@
1
+ # parent with helper methods
2
+ class ANN
3
+ private
4
+ ##
5
+ # define method with supplied name and block
6
+ def create_method(name, &block)
7
+ self.class.send(:define_method, name, &block)
8
+ end
9
+
10
+
11
+ # return hash of methods and returns excluding those in excludes
12
+ def to_hash(excludes)
13
+ # get list of methods excluding above
14
+ methods = self.class.instance_methods(false).reject {|m| excludes.include? m}
15
+
16
+ # map methods and results to hash
17
+ data = methods.map do |method |
18
+ result = self.send(method)
19
+
20
+ # convert Structs to hash
21
+ if (result.is_a? Array)
22
+ result.map! do |item|
23
+ item.is_a?(Struct) ? item.hash : item
24
+ end
25
+ else
26
+ result.hash! if result.is_a?(Struct)
27
+ end
28
+
29
+ # make hash with method name and result of call
30
+ [method.to_sym, result]
31
+ end
32
+
33
+ # return hash
34
+ Hash[data]
35
+ end
36
+ end
37
+
38
+ # various ANN struct types
39
+ ANN_Error = Struct.new(:message)
40
+ ANN_Staff = Struct.new(:id, :task, :name)
41
+ ANN_Cast = Struct.new(:id, :role, :name, :lang)
42
+ ANN_Episode = Struct.new(:number, :title, :lang)
43
+ ANN_Image = Struct.new(:src, :width, :height)
44
+ ANN_Rating = Struct.new(:votes, :weighted, :bayesian_score)
@@ -0,0 +1,85 @@
1
+ require_relative 'ann_media'
2
+
3
+ class ANN_Anime < ANN_Media
4
+ # ann_anime Nokogiri object
5
+ attr_writer :ann_anime
6
+
7
+
8
+ # initialize and create info methods
9
+ def initialize(ann_anime)
10
+ @ann_anime = ann_anime
11
+
12
+ # information available from detail
13
+ @info = Hash.new
14
+ @info[:title] = "Main title"
15
+ @info[:synopsis] = "Plot Summary"
16
+ @info[:num_episodes] = "Number of episodes"
17
+ @info[:genres] = "Genres"
18
+ @info[:themes] = "Themes"
19
+ @info[:vintage] = "Vintage"
20
+ @info[:op_theme] = "Opening Theme"
21
+ @info[:ed_theme] = "Ending Theme"
22
+
23
+ # create methods
24
+ create_methods(@ann_anime, @info)
25
+
26
+ end
27
+
28
+ # @return [Nokogiri::XML::NodeSet] return all info with provided key
29
+ def find_info(key)
30
+ super(@ann_anime, key)
31
+ end
32
+
33
+ # @return [String] returns anime id
34
+ def id
35
+ @id ||= @ann_anime['id']
36
+ end
37
+
38
+ # @return [String] returns anime type
39
+ def type
40
+ @type ||= @ann_anime['type']
41
+ end
42
+
43
+ # @return [[ANN_Rating]] returns array of ANN_Episode
44
+ def ratings
45
+ super @ann_anime
46
+ end
47
+
48
+ # @return [[ANN_Episode]] returns array of ANN_Episode
49
+ def episodes
50
+ @episodes ||= @ann_anime.xpath("./episode").map do |e|
51
+ title = e.at_xpath("title")
52
+ ANN_Episode.new(e['num'], title.content, title['lang'])
53
+ end
54
+ end
55
+
56
+ # @return [[ANN_Cast]] returns array of ANN_Cast
57
+ def cast
58
+ @cast ||= @ann_anime.xpath("./cast").map do |s|
59
+ role = s.at_xpath("role")
60
+ person = s.at_xpath("person")
61
+ ANN_Cast.new(person['id'], role.content, person.content, s['lang'])
62
+ end
63
+ end
64
+
65
+ # @return [[ANN_Staff]] returns array of ANN_Staff
66
+ def staff
67
+ super @ann_anime
68
+ end
69
+
70
+ # @return [Hash] hash of self
71
+ def to_h
72
+ # create hash excluding some methods
73
+ to_hash([:to_h, :ann_anime=, :find_info])
74
+ end
75
+
76
+ ##
77
+ # These methods are created via create_method in the constructor
78
+
79
+ # @return [[String]] returns number of episodes
80
+ def num_episodes; end
81
+ # @return [[String]] returns op theme(s)
82
+ def op_theme; end
83
+ # @return [[String]] returns ed theme(s)
84
+ def ed_theme; end
85
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'ann_media'
2
+
3
+ class ANN_Manga < ANN_Media
4
+ # ann_anime Nokogiri object
5
+ attr_writer :ann_manga
6
+
7
+ def initialize(ann_manga)
8
+ @ann_manga = ann_manga
9
+
10
+ # information available from detail
11
+ @info = Hash.new
12
+ @info[:title] = "Main title"
13
+ @info[:synopsis] = "Plot Summary"
14
+ @info[:genres] = "Genres"
15
+ @info[:vintage] = "Vintage"
16
+ @info[:themes] = "Themes"
17
+ @info[:num_tankoubon] = "Number of tankoubon"
18
+ @info[:num_pages] = "Number of pages"
19
+
20
+ # create methods
21
+ create_methods(@ann_manga, @info)
22
+ end
23
+
24
+ # @return [Nokogiri::XML::NodeSet] return all info with provided key
25
+ def find_info(key)
26
+ super(@ann_manga, key)
27
+ end
28
+
29
+ # @return [String] returns manga id
30
+ def id
31
+ @id ||= @ann_manga['id']
32
+ end
33
+
34
+ # @return [String] returns manga type
35
+ def type
36
+ @type ||= @ann_manga['type']
37
+ end
38
+
39
+ # @return [[ANN_Staff]] returns array of ANN_Staff
40
+ def staff
41
+ super @ann_manga
42
+ end
43
+
44
+ # @return [[ANN_Rating]] returns array of ANN_Episode
45
+ def ratings
46
+ super @ann_manga
47
+ end
48
+
49
+ # @return [Hash] hash of self
50
+ def to_h
51
+ # create hash excluding some methods
52
+ to_hash([:to_h, :ann_manga=, :find_info])
53
+ end
54
+
55
+ ##
56
+ # These methods are created via create_method in the constructor
57
+
58
+ # @return [[String]] returns the number of tankoubon
59
+ def num_tankoubon; end
60
+
61
+ # @return [[String]] returns the number of tankoubon
62
+ def num_pages; end
63
+ end