ruby-maidcafe 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 0.0.1 / 2007-06-24
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Rakefile
3
+ Manifest.txt
4
+ README.txt
5
+ bin/ruby-maidcafe
6
+ lib/ruby-maidcafe.rb
7
+ lib/cui.rb
8
+ test/test_ruby-maidcafe.rb
9
+ test/test_resultset.rb
10
+ test/data/shop_t_13.xml
11
+ test/data/t_list.xml
data/README.txt ADDED
@@ -0,0 +1,103 @@
1
+ ruby-maidcafe
2
+ by ANDO Yasushi (andyjpn@gmail.com)
3
+ (http://d.hatena.ne.jp/technohippy/)
4
+
5
+ == DESCRIPTION:
6
+
7
+ By utilizing this library, you can retrieve information of Japanese
8
+ Maidcafe via Maidcafe API web service (http://moeten.info/maidcafe/?m=api).
9
+ This can be used as interactive command line tool, non-interactive one,
10
+ and library.
11
+
12
+ == SYNOPSIS:
13
+
14
+ In your code:
15
+
16
+ * get shop list
17
+ api = Maidcafe::API.new
18
+ rs = api.list :shop
19
+ puts rs.description
20
+ rs.items.each do |item|
21
+ puts item.name
22
+ puts item.id
23
+ end
24
+ * get shop information in osaka
25
+ rs = api.shop :prefecture => Maidcafe::Prefecture::OSAKA
26
+ puts rs.description
27
+ rs.items.each do |item|
28
+ puts item.name
29
+ puts item.description
30
+ puts item.opening_hour
31
+ end
32
+
33
+ In your shell:
34
+
35
+ * get shop list
36
+ bin/ruby-maidcafe -s list
37
+ * get shop information in category #1
38
+ bin/ruby-maidcafe -c 1 shop
39
+ * get event information in osaka (#27)
40
+ bin/ruby-maidcafe -t 27 event
41
+ * interactive retrieval
42
+ $ bin/ruby-maidcafe
43
+
44
+ 1 : お店
45
+ 2 : 開催中のイベント
46
+ :
47
+ 8 : お店からのイベントのお知らせ
48
+ 選択してください: 1
49
+ お店
50
+
51
+ 都道府県名を指定しますか (y/N)y
52
+ 1 : 北海道
53
+ 2 : 栃木県
54
+ :
55
+ 10 : 鹿児島県
56
+ 選択してください: 1
57
+ 北海道
58
+
59
+ カテゴリを指定しますか (y/N)
60
+
61
+ お店番号を指定しますか (y/N)
62
+ 1 : ロミオ†ジュリエッタ - すべてがメイドさんの手作りメニュー☆
63
+ 2 : 萌えカフェ&BAR ゆるふわ - メイドさん達と楽しくお話しながら、...
64
+ 選択してください: 1
65
+ 店名:ロミオ†ジュリエッタ
66
+ Tel: 011-222-0832
67
+ 説明:すべてがメイドさんの手作りメニュー☆
68
+ 日替わりで担当のメイドがsweetsを作っています。
69
+ また、土日はランチもありますよ♪
70
+ メイドによりメニューは色々変わりますので
71
+ それもひとつのお楽しみです!
72
+ イベントも満載ですよ♪
73
+
74
+ [push enter key]
75
+
76
+ == INSTALL:
77
+
78
+ * gem instal ruby-maidcafe
79
+
80
+ == LICENSE:
81
+
82
+ (The MIT License)
83
+
84
+ Copyright (c) 2007 ANDO Yasushi
85
+
86
+ Permission is hereby granted, free of charge, to any person obtaining
87
+ a copy of this software and associated documentation files (the
88
+ 'Software'), to deal in the Software without restriction, including
89
+ without limitation the rights to use, copy, modify, merge, publish,
90
+ distribute, sublicense, and/or sell copies of the Software, and to
91
+ permit persons to whom the Software is furnished to do so, subject to
92
+ the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be
95
+ included in all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
98
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/ruby-maidcafe.rb'
6
+
7
+ Hoe.new('ruby-maidcafe', Maidcafe::VERSION) do |p|
8
+ p.rubyforge_name = 'ruby-maidcafe'
9
+ p.summary = 'ruby interface for Maidcafe API (http://moeten.info/maidcafe/?m=api)'
10
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
11
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
12
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
13
+ end
14
+
15
+ # vim: syntax=Ruby
data/bin/ruby-maidcafe ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # get category list in tokyo (13)
4
+ # bin/ruby-maidcafe -c list -t 13
5
+ #
6
+ # get shop list
7
+ # bin/ruby-maidcafe -s list
8
+ #
9
+ # get shop information
10
+ # bin/ruby-maidcafe -c 1 shop
11
+ #
12
+ # get event information in osaka
13
+ # bin/ruby-maidcafe -t 27 event
14
+
15
+ $KCODE = 'u'
16
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
17
+ require 'lib/ruby-maidcafe'
18
+
19
+ if ARGV.empty?
20
+ require 'lib/cui'
21
+ Maidcafe::CUI.start
22
+ else
23
+ require 'optparse'
24
+ COMMAND_LINE = "#{$0} #{ARGV.join(' ')}"
25
+ OPT = {}
26
+ opts = OptionParser.new
27
+ opts.on('-t <prefecture>'){|v| OPT[:tid] = v}
28
+ opts.on('-c <category>'){|v| OPT[:cid] = v}
29
+ opts.on('-s <shop>'){|v| OPT[:sid] = v}
30
+ opts.on('-g', '--gps <latlng>') do |v|
31
+ OPT[:gps_lat], OPT[:gps_lon] = latlng.split(',').map{|e| e.to_f}
32
+ end
33
+ opts.on('-w', '--wgps <latlng>') do |v|
34
+ OPT[:wgps_lat], OPT[:wgps_lon] = latlng.split(',').map{|e| e.to_f}
35
+ end
36
+ opts.on_tail('-v', '--version', 'Show version.'){puts(opts.ver); exit}
37
+ opts.on_tail('-h', '--help', 'Show this message.'){puts(opts.help); exit}
38
+
39
+ ::Version = Maidcafe::VERSION
40
+ opts.order! ARGV
41
+ CMD = ARGV.shift
42
+
43
+ api = Maidcafe::API.new
44
+ rs = api.invoke(CMD, OPT)
45
+ rs.items.each do |item|
46
+ puts item.to_s
47
+ puts
48
+ end
49
+ end
data/lib/cui.rb ADDED
@@ -0,0 +1,71 @@
1
+ module Maidcafe
2
+ module CUI
3
+ def prompt(api, condition, mandatory=false)
4
+ puts
5
+ unless mandatory
6
+ print "#{{:tid => '都道府県名', :cid => 'カテゴリ', :sid => 'お店番号'}[condition]}を指定しますか (y/N)"
7
+ return nil unless gets =~ /[yY]/
8
+ end
9
+ rs = api.invoke nil, condition => 'list'
10
+ rs.items.each_with_index do |t, index|
11
+ puts "#{index+1} : #{t.name}"
12
+ end
13
+ print '選択してください: '
14
+ input = gets
15
+ exit if input =~ /^\s*(quit|exit)\s*$/i
16
+ type_id = input.to_i
17
+ type_id <= 0 ? nil : rs.items[type_id - 1]
18
+ end
19
+
20
+ def puts_name(obj)
21
+ puts obj.name if obj
22
+ end
23
+
24
+ def show_opt(opt, key, obj)
25
+ puts_name obj
26
+ opt[key] = obj.id if obj
27
+ end
28
+
29
+ def start
30
+ api = Maidcafe::API.new
31
+ type = nil
32
+ while !type
33
+ type = prompt api, :type, true
34
+ end
35
+ puts_name type
36
+
37
+ opts = {}
38
+
39
+ prefecture = prompt api, :tid
40
+ show_opt opts, :tid, prefecture
41
+
42
+ category = prompt api, :cid
43
+ show_opt opts, :cid, category
44
+
45
+ shop = prompt api, :sid
46
+ show_opt opts, :sid, shop
47
+
48
+ rs = api.invoke type.keytype, opts
49
+ while true
50
+ if rs.items.empty?
51
+ puts "データが存在しません"
52
+ exit
53
+ end
54
+ rs.items.each_with_index do |i, index|
55
+ puts "#{index+1} : #{i.name} - #{i.description.split("\n")[0]}"
56
+ end
57
+ print '選択してください: '
58
+ input = gets
59
+ exit if input =~ /^\s*(quit|exit)\s*$/i
60
+ item_id = input.to_i
61
+ if 0 < item_id
62
+ puts rs.items[item_id - 1].to_s
63
+ end
64
+ puts "\n[push enter key]"
65
+ gets
66
+ end
67
+ end
68
+
69
+ module_function :start, :prompt, :puts_name, :show_opt
70
+ end
71
+ end
@@ -0,0 +1,231 @@
1
+ require 'erb'
2
+ require 'open-uri'
3
+ require 'rexml/document'
4
+
5
+ def dputs(str)
6
+ puts str if $DEBUG
7
+ end
8
+
9
+ module Maidcafe
10
+ VERSION = '0.0.1'
11
+
12
+ class API
13
+ BASE_URL = 'http://moeten.info/maidcafe'
14
+
15
+ def list(type)
16
+ case type
17
+ when :type
18
+ invoke 'list'
19
+ when :tid, :prefecture
20
+ invoke nil, :tid => 'list'
21
+ when :cid, :category
22
+ invoke nil, :cid => 'list'
23
+ when :sid, :shop
24
+ invoke nil, :sid => 'list'
25
+ else
26
+ throw ArgumentError.new
27
+ end
28
+ end
29
+
30
+ def read(type, args)
31
+ open(request_url(type, args)) {|f| REXML::Document.new f}.write
32
+ end
33
+
34
+ def invoke(type, args=[])
35
+ url = request_url(type, args)
36
+ dputs "access to #{url}"
37
+ ResultSet.new(type, open(url) {|f| REXML::Document.new f})
38
+ end
39
+
40
+ def request_url(type, args)
41
+ type_arg = type ? "type=#{type}" : ''
42
+ other_args = args.to_a.map{|e| "#{e[0]}=#{e[1]}"}.join '&'
43
+ "#{BASE_URL}/?#{type_arg}&#{other_args}&m=api"
44
+ end
45
+
46
+ def method_missing(name, *args, &block)
47
+ invoke name, args
48
+ end
49
+ end
50
+
51
+ class ResultItem
52
+ def initialize(xml)
53
+ read xml
54
+ end
55
+
56
+ def read(xml)
57
+ attr_to_tag.each do |attr, tag|
58
+ send "#{attr}=", element_text(xml, tag)
59
+ end
60
+ end
61
+
62
+ def attr_to_tag
63
+ {}
64
+ end
65
+
66
+ def element_text(xml, tag)
67
+ (tag = xml.elements[tag]) ? tag.text : nil
68
+ end
69
+
70
+ def to_s
71
+ "ID: #{id}\n名前: #{name}"
72
+ end
73
+ end
74
+
75
+ class ResultSet < ResultItem
76
+ attr_accessor :title, :link, :description, :language, :generator, :items
77
+
78
+ def initialize(type, xml)
79
+ @items = []
80
+ read xml
81
+ xml.elements.each('channel/item') do |item|
82
+ @items.push(
83
+ if item.elements['image']; Moe.new(type, item)
84
+ elsif item.elements['tid']; Prefecture.new(item)
85
+ elsif item.elements['cid']; Category.new(item)
86
+ elsif item.elements['sid']; Shop.new(item)
87
+ elsif item.elements['keytype']; Type.new(item)
88
+ else; raise ArgumentError.new(item.inspect)
89
+ end
90
+ )
91
+ end
92
+ end
93
+
94
+ def attr_to_tag
95
+ {:title => 'channel/title', :link => 'channel/link', :description => 'channel/description',
96
+ :language => 'channel/language', :generator => 'channel/generator'}
97
+ end
98
+ end
99
+
100
+ class Location
101
+ attr_accessor :latitude, :longitude
102
+ def initialize(lat, lng)
103
+ @latitude = lat
104
+ @longitude = lng
105
+ end
106
+ end
107
+
108
+ class Moe < ResultItem
109
+ attr_accessor :name, :category, :prefecture, :description, :images,
110
+ :url, :url_mobile, :tel, :address, :gps, :wgps, :map_urls
111
+
112
+ def initialize(type, xml)
113
+ read(xml)
114
+ @specialities = self.class.const_get(type.to_s.capitalize).new(xml)
115
+ @images = [element_text(xml, 'image/image1'),
116
+ element_text(xml, 'image/image2'),
117
+ element_text(xml, 'image/image3')].compact
118
+ @map_urls = [element_text(xml, 'map/map_livedoor'),
119
+ element_text(xml, 'map/map_navitime'),
120
+ element_text(xml, 'map/map_mapfan'),
121
+ element_text(xml, 'map/map_mapion'),
122
+ element_text(xml, 'map/map_googlemap'),
123
+ element_text(xml, 'map/map_alps')].compact
124
+ @gps = Location.new element_text(xml, 'gps_lat'), element_text(xml, 'gps_lon')
125
+ @wgps = Location.new element_text(xml, 'wgps_lat'), element_text(xml, 'wgps_lon')
126
+ end
127
+
128
+ def attr_to_tag
129
+ {:name => 'shopname', :category => 'category', :prefecture => 'todouhuken',
130
+ :description => 'setumei', :url => 'url', :url_mobile => 'url_mobile',
131
+ :tel => 'tel', :address => 'address'}
132
+ end
133
+
134
+ def to_s
135
+ ERB.new(<<-end_of_template).result(binding)
136
+ 店名: <%= name %>
137
+ 住所: <%= address %>
138
+ Tel: <%= tel %>
139
+ 説明: <%= description.gsub("\n", "\n ").chomp %>
140
+ end_of_template
141
+ end
142
+
143
+ def method_missing(name, *args, &block)
144
+ @specialities.send name, *args
145
+ end
146
+
147
+ class Shop < ResultItem
148
+ attr_accessor :opening_hour, :menu
149
+ def attr_to_tag; {:opening_hour => 'eigyoujikan', :menu => 'menu'} end
150
+ end
151
+
152
+ class Event < ResultItem
153
+ end
154
+
155
+ class Coupon < ResultItem
156
+ attr_accessor :coupon, :submit_condition, :number_condition
157
+ def attr_to_tag
158
+ {:coupon => 'coupon', :submit_condition => 'teiji_zyouken',
159
+ :number_condition => 'riyou_zyouken'}
160
+ end
161
+ end
162
+
163
+ class Baito < ResultItem
164
+ attr_accessor :hourly_wage, :work_hours, :ages, :hischool, :cv, :interview_time, :q_and_a
165
+ def attr_to_tag
166
+ {:hourly_wage => 'jikyuu', :work_hours => 'kinmujikan', :ages => 'nenren',
167
+ :hischool => 'koukousei', :cv => 'rirekisyo', :interview_time => 'mensetubi',
168
+ :q_and_a => 'qanda'}
169
+ end
170
+ end
171
+
172
+ class Opendate < ResultItem
173
+ end
174
+
175
+ class Newshop < ResultItem
176
+ attr_accessor :date, :wdate
177
+ def attr_to_tag; {:date => 'date', :wdate => 'mdate'} end
178
+ end
179
+
180
+ class Dayinfo < ResultItem
181
+ end
182
+
183
+ class Eventinfo < ResultItem
184
+ end
185
+ end
186
+
187
+ class Type < ResultItem
188
+ SHOP = 'shop'
189
+ EVENT = 'event'
190
+ COUPON = 'coupon'
191
+ BAITO = 'baito'
192
+ OPENDATE = 'opendate'
193
+ NEWSHOP = 'newshop'
194
+ DAYINFO = 'dayinfo'
195
+ EVENTINFO = 'eventinfo'
196
+
197
+ attr_accessor :type, :keytype
198
+ def attr_to_tag; {:type => 'type', :keytype => 'keytype'} end
199
+ def name; type end
200
+ end
201
+
202
+ class Prefecture < ResultItem
203
+ ANY = nil
204
+ HOKAIDO = 1
205
+ TOCHIGI = 9
206
+ SAITAMA = 11
207
+ TOKYO = 13
208
+ KANAGAWA = 14
209
+ GIFU = 21
210
+ AICHI = 23
211
+ OSAKA = 27
212
+ FUKUOKA = 40
213
+ KAGOSHIMA = 46
214
+
215
+ attr_accessor :name, :tid
216
+ def attr_to_tag; {:name => 'todouhuken', :tid => 'tid'} end
217
+ def id; tid end
218
+ end
219
+
220
+ class Category < ResultItem
221
+ attr_accessor :name, :cid
222
+ def attr_to_tag; {:name => 'category', :cid => 'cid'} end
223
+ def id; cid end
224
+ end
225
+
226
+ class Shop < ResultItem
227
+ attr_accessor :name, :sid
228
+ def attr_to_tag; {:name => 'shopname', :sid => 'sid'} end
229
+ def id; sid end
230
+ end
231
+ end