syobocal 0.10.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b32b7dbb64cf8d4b48bd87da408f5607b845ab85073c025327bc6e9d6294df6
4
- data.tar.gz: 4f2ed089906d9f1560d5b0aeeaa0f009d284337069cc2794521e235ee082899c
3
+ metadata.gz: 737c5456c21b70925571795e9b8f81b35ba89738065dfaec3332c11d3920e19f
4
+ data.tar.gz: 26ef1a657a390e37fef06c2a0ac7ed681a3bbd951fb6f779f248a61bc08aaddd
5
5
  SHA512:
6
- metadata.gz: a29a2ba9cfb401f13fc69862cb283f9081fe55edb26e26618649393d0de42c97ce3759a9be5345d8bb852c59d1af453b5d4f66485dbc788851cdc7e9419cce2c
7
- data.tar.gz: 8f71e8e5941a9a40837648e9300d7cd110b1512f00bc0169185206e12e709c0a1e7c1943e8710a55684c361da01a981459511180cb217db5f425043664dc6d5b
6
+ metadata.gz: cb49862e127d7abba99f6a09fe93e2f357d4e331243e6236314c23c1d9e5384cd39af7501009c77ab07ac0a7f8a00ae71082f5f5b6fbb1060da31051160d03b7
7
+ data.tar.gz: 3aaf9a0a8bdfbf76e703608dadbd97d6f6971ec787772e0507aeeae47109dc179654e5fd56c4e50e0b691df8df5c8cd3525f7395d42c0e43f68de059038efa60
data/README.md CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  ## 概要
4
4
 
5
- syobocalは[しょぼいカレンダー](http://cal.syoboi.jp/)からデータを取得するためのRubyスクリプトです。
6
- sch_uploadを除いて仕様が公開されている以下20種類のエンドポイントすべてに対応しています。
5
+ syobocalは[しょぼいカレンダー](http://cal.syoboi.jp/)からデータを取得するためのRubyスクリプトです。`sch_upload`を除いて仕様が公開されている以下20種類のエンドポイントすべてに対応しています。
7
6
 
8
7
  - cal_chk.php
9
8
  - db.php
@@ -49,12 +48,180 @@ sch_uploadを除いて仕様が公開されている以下20種類のエンド
49
48
  XMLやRSSをパースした結果は値が適切な型に変換されたハッシュの配列です。
50
49
  JSONをパースした結果はJSONのデータ構造をそのまま返します。
51
50
 
52
- ~~~~
51
+ いくつか典型的だろう使い方を紹介します。
52
+
53
+ 以下は`db.php`からアニメごとに採番された`TID`とタイトルを一覧で取得する例です。
54
+
55
+ ```ruby
53
56
  require 'syobocal'
54
57
  require 'pp'
55
- params = {"TID" => "1"}
56
- pp Syobocal::DB::TitleLookup.get(params)
57
- ~~~~
58
+
59
+ pp Syobocal::DB::TitleLookup.get({'TID' => '*', 'Fields' => 'TID,Title'})
60
+ # [{:tid=>1, :title=>"魔法遣いに大切なこと"},
61
+ # {:tid=>2, :title=>"ソニックX"},
62
+ # {:tid=>3, :title=>"デ・ジ・キャラットにょ"},
63
+ # {:tid=>1224, :title=>"魔法先生ネギま!(実写版)"},
64
+ # {:tid=>3601, :title=>"新妹魔王の契約者"},
65
+ # {:tid=>3588, :title=>"アイドルマスター シンデレラガールズ"},
66
+ # {:tid=>4, :title=>"妄想科学シリーズ ワンダバスタイル"},
67
+ # {:tid=>1086, :title=>"ひとひら"},
68
+ # {:tid=>5, :title=>"DEARBOYS"},
69
+ # {:tid=>6, :title=>"LAST EXILE"},
70
+ # ...
71
+ ```
72
+
73
+ 以下は`TID`指定で特定のアニメのデータを取得する例です。
74
+
75
+ ```ruby
76
+ require 'syobocal'
77
+ require 'pp'
78
+
79
+ title = Syobocal::DB::TitleLookup.get({'TID' => '2077'})
80
+ pp title.first
81
+ # {:tid=>2077,
82
+ # :last_update=>2013-12-02 02:17:55 +0900,
83
+ # :title=>"魔法少女まどか☆マギカ",
84
+ # :short_title=>"まどか☆マギカ",
85
+ # :title_yomi=>"まほうしょうじょまどかまぎか",
86
+ # :title_en=>"PUELLA MAGI MADOKA MAGICA",
87
+ # :comment=>
88
+ # "*リンク\n" +
89
+ # "-[[公式 http://www.madoka-magica.com/tv/]]\n" +
90
+ # "-[[MBS http://www.mbs.jp/madoka-magica/]]\n" +
91
+ # "-[[ニコニコチャンネル http://ch.nicovideo.jp/ch260]]\n" +
92
+ # "-[[TOKYO MX http://www.mxtv.co.jp/madoka_magica/]]\n" +
93
+ # "-[[BS11デジタル http://www.bs11.jp/anime/2360/]]\n" +
94
+ # "*メモ\n" +
95
+ # "-アニマックスでのリピート放送は放送日の27:00~と日曜26:00~\n" +
96
+ # "*スタッフ\n" +
97
+ # ":原作:Magica Quartet\n" +
98
+ # ":監督:新房昭之\n" +
99
+ # ":キャラクター原案:蒼樹うめ\n" +
100
+ # ":キャラクターデザイン:岸田隆宏\n" +
101
+ # ...
102
+ ```
103
+
104
+ APIリクエスト時のパラメータは`syobocal`ライブラリとして解釈しません。しょぼいカレンダーのAPI仕様を参照して下さい。また`'TID' => '*'`に代表される大量のデータ取得はしばしば10MB以上の巨大なレスポンスを返します。しょぼいカレンダー側も大変だろうと思うので、使い方は考えて下さい。
105
+
106
+ ### コメントパーサ(ベータ版)
107
+
108
+ しょぼいカレンダーの`comment`属性にはスタッフやキャストなど多岐に渡る情報が専用の記法で格納されています。バージョン`0.11`以降の`syobocal`ライブラリはコメントパーサ(`Syobocal::Comment::Parser`)を備え、それらの情報を意味的に扱いやすい形で取り出すことができます。コメントパーサはベータ版です。インタフェースは変更される可能性があります。
109
+
110
+ ```ruby
111
+ require 'syobocal'
112
+ require 'pp'
113
+
114
+ title = Syobocal::DB::TitleLookup.get({'TID' => '2077'})
115
+ comment = title.first[:comment]
116
+ parser = Syobocal::Comment::Parser.new(comment)
117
+
118
+ pp parser.links.first
119
+ # #<Syobocal::Comment::Element::Link:0x0000564600b42e30
120
+ # @str="公式",
121
+ # @url="http://www.madoka-magica.com/tv/">
122
+
123
+ pp parser.staffs.first
124
+ # #<Syobocal::Comment::Staff:0x00005645ffc60048
125
+ # @people=
126
+ # [#<Syobocal::Comment::Person:0x00005645ffc60368
127
+ # @name="Magica Quartet",
128
+ # @note=nil>],
129
+ # @role="原作">
130
+
131
+ pp parser.casts.first
132
+ # #<Syobocal::Comment::Cast:0x0000564600051b70
133
+ # @character="鹿目まどか",
134
+ # @people=
135
+ # [#<Syobocal::Comment::Person:0x0000564600051cd8 @name="悠木碧", @note=nil>]>
136
+
137
+ pp parser.musics.first
138
+ # #<Syobocal::Comment::Music:0x0000561287c8f1a0
139
+ # @category="オープニングテーマ",
140
+ # @data_list=
141
+ # [#<Syobocal::Comment::MusicData:0x0000561287c8b8e8
142
+ # @attr="作詞・作曲",
143
+ # @attr_note=nil,
144
+ # @attr_text="作詞・作曲",
145
+ # @people=
146
+ # [#<Syobocal::Comment::Person:0x0000561287c8ba28 @name="渡辺翔", @note=nil>],
147
+ # @value="渡辺翔">,
148
+ # #<Syobocal::Comment::MusicData:0x0000561287c8a3d0
149
+ # @attr="主題歌協力",
150
+ # @attr_note=nil,
151
+ # @attr_text="主題歌協力",
152
+ # @people=
153
+ # [#<Syobocal::Comment::Person:0x0000561287c8a510 @name="外村敬一", @note=nil>],
154
+ # @value="外村敬一">,
155
+ # #<Syobocal::Comment::MusicData:0x0000561287c88e90
156
+ # @attr="歌",
157
+ # @attr_note=nil,
158
+ # @attr_text="歌",
159
+ # @people=
160
+ # [#<Syobocal::Comment::Person:0x0000561287c88fd0
161
+ # @name="ClariS",
162
+ # @note=nil>],
163
+ # @value="ClariS">,
164
+ # #<Syobocal::Comment::MusicData:0x0000561287c8f2e0
165
+ # @attr="使用話数",
166
+ # @attr_note=nil,
167
+ # @attr_text="使用話数",
168
+ # @people=
169
+ # [#<Syobocal::Comment::Person:0x0000561287c8f560 @name="#1~#9", @note=nil>,
170
+ # #<Syobocal::Comment::Person:0x0000561287c8f420 @name="#11", @note=nil>],
171
+ # @value="#1~#9、#11">],
172
+ # @title="コネクト">
173
+ ```
174
+
175
+ ### サブタイトルパーサ(ベータ版)
176
+
177
+ しょぼいカレンダーの`sub_titles`属性をパースして扱いやすい形にして取り出すパーサです。
178
+
179
+ ```ruby
180
+ require 'syobocal'
181
+ require 'pp'
182
+
183
+ title = Syobocal::DB::TitleLookup.get({'TID' => '2077'})
184
+ sub_titles = title.first[:sub_titles]
185
+ parser = Syobocal::SubTitles::Parser.new(sub_titles)
186
+
187
+ pp parser.parse
188
+ # [#<Syobocal::SubTitles::SubTitle:0x00005591edc37830
189
+ # @episode="01",
190
+ # @title="夢の中で会った、ような・・・・・">,
191
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc37448
192
+ # @episode="02",
193
+ # @title="それはとっても嬉しいなって">,
194
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc370b0
195
+ # @episode="03",
196
+ # @title="もう何も恐くない">,
197
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc36d40
198
+ # @episode="04",
199
+ # @title="奇跡も、魔法も、あるんだよ">,
200
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc36c00
201
+ # @episode="05",
202
+ # @title="後悔なんて、あるわけない">,
203
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc36700
204
+ # @episode="06",
205
+ # @title="こんなの絶対おかしいよ">,
206
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc36408
207
+ # @episode="07",
208
+ # @title="本当の気持ちと向き合えますか?">,
209
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc36110
210
+ # @episode="08",
211
+ # @title="あたしって、ほんとバカ">,
212
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc35c88
213
+ # @episode="09",
214
+ # @title="そんなの、あたしが許さない">,
215
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc34d38
216
+ # @episode="10",
217
+ # @title="もう誰にも頼らない">,
218
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc34a68
219
+ # @episode="11",
220
+ # @title="最後に残った道しるべ">,
221
+ # #<Syobocal::SubTitles::SubTitle:0x00005591edc34900
222
+ # @episode="12",
223
+ # @title="わたしの、最高の友達">]
224
+ ```
58
225
 
59
226
  ## おまけ
60
227
 
@@ -109,7 +276,7 @@ $ syobocal-anime
109
276
 
110
277
  ## 作者
111
278
 
112
- - [xmisao](http://www.xmisao.com/)
279
+ - [xmisao](https://www.xmisao.com/)
113
280
 
114
281
  ## ライセンス
115
282
 
data/Rakefile CHANGED
@@ -1,2 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
data/data/.gitkeep ADDED
File without changes
@@ -1,11 +1,11 @@
1
1
  module Syobocal
2
2
  module CalChk
3
3
  def get(params = {})
4
- parse(open(url(params)))
4
+ parse(URI.open(url(params)))
5
5
  end
6
6
 
7
7
  def url(params = {})
8
- 'http://cal.syoboi.jp/cal_chk.php' + Syobocal::Util.format_params(params)
8
+ "http://cal.syoboi.jp/cal_chk.php" + Syobocal::Util.format_params(params)
9
9
  end
10
10
 
11
11
  def parse(xml)
@@ -13,14 +13,14 @@ module Syobocal
13
13
 
14
14
  result = Result.new
15
15
 
16
- syobocal = xml.elements['syobocal']
16
+ syobocal = xml.elements["syobocal"]
17
17
  result.url = syobocal.attribute("url").to_s
18
18
  result.version = syobocal.attribute("version").to_s
19
19
  result.last_update = Time.parse(syobocal.attribute("LastUpdate").to_s)
20
20
  result.spid = syobocal.attribute("SPID").to_s
21
21
  result.spname = syobocal.attribute("SPNAME").to_s
22
22
 
23
- xml.elements.each('syobocal/ProgItems/ProgItem'){|item|
23
+ xml.elements.each("syobocal/ProgItems/ProgItem") { |item|
24
24
  result << {
25
25
  :pid => item.attribute("PID").to_s.to_i,
26
26
  :tid => item.attribute("TID").to_s.to_i,
@@ -32,7 +32,7 @@ module Syobocal
32
32
  :st_offset => item.attribute("StOffset").to_s.to_i,
33
33
  :sub_title => item.attribute("SubTitle").to_s,
34
34
  :title => item.attribute("Title").to_s,
35
- :prog_comment => item.attribute("ProgComment").to_s
35
+ :prog_comment => item.attribute("ProgComment").to_s,
36
36
  }
37
37
  }
38
38
 
@@ -0,0 +1,15 @@
1
+ module Syobocal
2
+ module Comment
3
+ class Cast
4
+ attr_reader :character, :people
5
+
6
+ def initialize(character, people)
7
+ @character, @people = character, people
8
+ end
9
+
10
+ def ==(other)
11
+ other.instance_of?(self.class) && other.character == character && other.people == people
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Blank
5
+ def initialize; end
6
+
7
+ def ==(other)
8
+ other.instance_of?(self.class)
9
+ end
10
+
11
+ def inner_text
12
+ ""
13
+ end
14
+
15
+ def self.match?(line)
16
+ line.match(/\A\s*\Z/)
17
+ end
18
+
19
+ def self.parse(line)
20
+ Element::Blank.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Header1
5
+ attr_reader :text_node
6
+
7
+ def initialize(text_node)
8
+ @text_node = text_node
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.text_node == text_node
13
+ end
14
+
15
+ def self.match?(line)
16
+ !Header2.match?(line) && line.start_with?("*")
17
+ end
18
+
19
+ def self.parse(line)
20
+ txt = line.match(/\A\*(.*)\Z/)[1]
21
+
22
+ Element::Header1.new(Element::TextNode.parse(txt))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Header2
5
+ attr_reader :text_node
6
+
7
+ def initialize(text_node)
8
+ @text_node = text_node
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.text_node == text_node
13
+ end
14
+
15
+ def self.match?(line)
16
+ line.start_with?("**")
17
+ end
18
+
19
+ def self.parse(line)
20
+ txt = line.match(/\A\*\*(.*)\Z/)[1]
21
+
22
+ Element::Header2.new(Element::TextNode.parse(txt))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Link
5
+ attr_reader :str, :url
6
+
7
+ def initialize(str, url)
8
+ @str, @url = str, url
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.str == str && other.url == url
13
+ end
14
+
15
+ def self.create(text)
16
+ inner_str = text.match(/\A\[\[(.*)\]\]\Z/)[1]
17
+
18
+ sep = inner_str.split(/ /)
19
+
20
+ if ["http://", "https://", "archive://"].any? { |scheme| sep.last.start_with?(scheme) }
21
+ link = sep.pop
22
+ new(sep.join(" "), link)
23
+ else
24
+ new(sep.join(" "), nil)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class List
5
+ attr_reader :text_node
6
+
7
+ def initialize(text_node)
8
+ @text_node = text_node
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.text_node == text_node
13
+ end
14
+
15
+ def self.match?(line)
16
+ line.start_with?("-")
17
+ end
18
+
19
+ def self.parse(line)
20
+ txt = line.match(/\A-(.*)\Z/)[1]
21
+
22
+ Element::List.new(Element::TextNode.parse(txt))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Root
5
+ attr_reader :elements
6
+
7
+ def initialize(elements)
8
+ @elements = elements
9
+ end
10
+
11
+ def ==(other)
12
+ other.elements == elements
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Row
5
+ attr_reader :attr_node, :value_node
6
+
7
+ def initialize(attr_node, value_node)
8
+ @attr_node, @value_node = attr_node, value_node
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.attr_node == attr_node && other.value_node == value_node
13
+ end
14
+
15
+ def self.match?(line)
16
+ line.start_with?(":")
17
+ end
18
+
19
+ def self.parse(line)
20
+ if line.scan(":").length == 1
21
+ # NOTE :が1つしか含まれない行は:以降が値となる
22
+ m = line.match(/\A:(.*)\Z/)
23
+ attr = Element::Blank.new
24
+ value = Element::TextNode.parse(m[1])
25
+ else
26
+ m = line.match(/\A:([^:]*?):(.*)\Z/)
27
+ attr = Element::TextNode.parse(m[1])
28
+ value = Element::TextNode.parse(m[2])
29
+ end
30
+
31
+ Element::Row.new(attr, value)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class Text
5
+ attr_reader :str
6
+
7
+ def initialize(str)
8
+ @str = str
9
+ end
10
+
11
+ def ==(other)
12
+ other.instance_of?(self.class) && other.str == str
13
+ end
14
+
15
+ def self.create(text)
16
+ new(text)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Element
4
+ class TextNode
5
+ attr_reader :text_elements
6
+
7
+ SUBJECT_SEPARATOR = "、"
8
+ ENCODED_SEPARATOR = "\t"
9
+
10
+ def initialize(text_elements)
11
+ @text_elements = text_elements
12
+ end
13
+
14
+ def inner_text
15
+ text_elements.map(&:str).join("")
16
+ end
17
+
18
+ def ==(other)
19
+ other.instance_of?(self.class) && other.text_elements == text_elements
20
+ end
21
+
22
+ def split
23
+ buffer = ""
24
+
25
+ text_elements.each do |node|
26
+ case node
27
+ when Element::Text
28
+ buffer << node.str.gsub(SUBJECT_SEPARATOR, ENCODED_SEPARATOR)
29
+ when Element::Link
30
+ buffer << node.str
31
+ end
32
+ end
33
+
34
+ buffer.scan(/[^#{ENCODED_SEPARATOR}\(]+(?:\(.*?\))?/).map { |str| str.gsub(ENCODED_SEPARATOR, SUBJECT_SEPARATOR).strip }
35
+ end
36
+
37
+ def self.match?(line)
38
+ true
39
+ end
40
+
41
+ def self.parse(text)
42
+ elements = text.split(/(\[\[[^\[\]]*?\]\])/).select { |s| !s.empty? }.map do |s|
43
+ if s.match(/\A\[\[[^\[\]]*?\]\]\Z/)
44
+ Link.create(s)
45
+ else
46
+ Text.create(s)
47
+ end
48
+ end
49
+
50
+ Element::TextNode.new(elements)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,80 @@
1
+ module Syobocal
2
+ module Comment
3
+ module Helper
4
+ class Fragment
5
+ CHILD_BEGIN = '('
6
+ CHILD_END = ')'
7
+ SEPARATOR = '、'
8
+
9
+ attr_reader :text, :child, :following
10
+
11
+ def initialize(text, child, following)
12
+ @text, @child, @following = text, child, following
13
+ end
14
+
15
+ def self.parse(str)
16
+ chars = str.each_char.to_a
17
+
18
+ parse_chars(chars)
19
+ end
20
+
21
+ def self.parse_chars(chars)
22
+ text = ""
23
+ child = nil
24
+ following = nil
25
+
26
+ until chars.empty?
27
+ c = chars.shift
28
+
29
+ case c
30
+ when CHILD_BEGIN
31
+ child = parse_chars(chars)
32
+ when CHILD_END
33
+ return Fragment.new(text, child, following)
34
+ when SEPARATOR
35
+ following = parse_chars(chars)
36
+ else
37
+ text << c
38
+ end
39
+ end
40
+
41
+ Fragment.new(text, child, following)
42
+ end
43
+
44
+ def pretty_output(level = 0)
45
+ line = level.times.map{' '}.join
46
+
47
+ line << text
48
+
49
+ puts line
50
+
51
+ child&.pretty_output(level + 1)
52
+
53
+ following&.pretty_output(level)
54
+ end
55
+
56
+ def to_a
57
+ array = [self]
58
+ target = self
59
+
60
+ while target.following
61
+ array << target.following
62
+ target = target.following
63
+ end
64
+
65
+ array
66
+ end
67
+
68
+ def to_s
69
+ to_a.map{|f|
70
+ if f.child
71
+ "#{f.text}(#{f.child.to_s})"
72
+ else
73
+ "#{f.text}"
74
+ end
75
+ }.join(SEPARATOR)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,15 @@
1
+ module Syobocal
2
+ module Comment
3
+ class Music
4
+ attr_reader :title, :category, :data_list
5
+
6
+ def initialize(title, category, data_list)
7
+ @title, @category, @data_list = title, category, data_list
8
+ end
9
+
10
+ def ==(other)
11
+ other.instance_of?(self.class) && other.title == title && other.category == category && other.data_list == data_list
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Syobocal
2
+ module Comment
3
+ class MusicData
4
+ attr_reader :attr, :attr_text, :attr_note, :value, :people
5
+
6
+ def initialize(attr, attr_text, attr_note, value, people)
7
+ @attr, @attr_text, @attr_note, @value, @people = attr, attr_text, attr_note, value, people
8
+ end
9
+
10
+ def ==(other)
11
+ other.instance_of?(self.class) && other.attr == attr && other.attr_text == attr_text && other.attr_note == other.attr_note && other.value == value && other.people == people
12
+ end
13
+ end
14
+ end
15
+ end