corich_stage 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dd8771af9b1f797fea78523e08fd3ca0737eb874cb09143600e1b10dbb2679cf
4
+ data.tar.gz: be7aead12b75f22d0e67fd1a1a1dc94423d396d6e595676d4ab100390df5fd65
5
+ SHA512:
6
+ metadata.gz: b866391d145161ea1ab2beff94532d424ef6d5ffc093bc5483161dd6933b45abd790baef902839043716efea15feef61003c2186ad2169f116e06c7318a61f4a
7
+ data.tar.gz: '028f578c4c14bab82d53902e79d57bc5bf69b7f7bf560e445f42eb4c6de50207b0e4863ca3331e01b81d1b70771e349073b2d73923239009d5a0f2b5e5f9df91'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ryu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # corich_stage
2
+
3
+ [CoRich舞台芸術](https://stage.corich.jp)から公演情報をスクレイピングするRuby gem。
4
+
5
+ ## インストール
6
+
7
+ ```ruby
8
+ # Gemfile
9
+ gem "corich_stage", github: "ryu/corich_stage"
10
+
11
+ # ローカル開発
12
+ gem "corich_stage", path: "../corich_stage"
13
+ ```
14
+
15
+ ## 使い方
16
+
17
+ ### 公演一覧の取得
18
+
19
+ ```ruby
20
+ # 東京の公演一覧(デフォルト: 90日先まで)
21
+ summaries = CorichStage.search
22
+
23
+ # 基準日を指定(デフォルト: 今日)
24
+ summaries = CorichStage.search(date: Date.new(2026, 4, 1))
25
+
26
+ # 日付範囲を変更
27
+ summaries = CorichStage.search(days_ahead: 30)
28
+
29
+ # 組み合わせ: 4月1日から30日先まで
30
+ summaries = CorichStage.search(date: Date.new(2026, 4, 1), days_ahead: 30)
31
+
32
+ # ページ数制限
33
+ summaries = CorichStage.search(max_pages: 3)
34
+
35
+ summary = summaries.first
36
+ summary.stage_id #=> "431567"
37
+ summary.title #=> "闇に咲く花"
38
+ summary.venue #=> "紀伊國屋サザンシアター TAKASHIMAYA"
39
+ summary.period #=> "2026/03/28 (土) ~ 2026/04/19 (日)"
40
+ summary.start_date #=> #<Date: 2026-03-28>
41
+ summary.end_date #=> #<Date: 2026-04-19>
42
+ ```
43
+
44
+ ### 公演詳細の取得
45
+
46
+ ```ruby
47
+ stage = CorichStage.fetch("431567")
48
+
49
+ stage.title #=> "闇に咲く花"
50
+ stage.company #=> "こまつ座"
51
+ stage.director_name #=> "大河内直子"
52
+ stage.playwright_name #=> "井上ひさし"
53
+ stage.venue #=> "紀伊國屋サザンシアター TAKASHIMAYA"
54
+ stage.period #=> "2026/03/28 (土) ~ 2026/04/19 (日)"
55
+ stage.prices #=> "3,000円 ~ 9,500円"
56
+ stage.duration #=> "約3時間0分(休憩含む)を予定"
57
+ stage.cast #=> "筧利夫、諏訪珠理、佐藤正宏、..."
58
+ stage.description #=> "昭和20年、東京の下町..."
59
+ stage.staff #=> "作・演出・音楽:糸井幸之介..."
60
+ stage.official_site #=> "https://komatsuza.co.jp/..."
61
+ ```
62
+
63
+ ### ヘルパーメソッド
64
+
65
+ ```ruby
66
+ stage.duration_minutes #=> 180 "約3時間0分" → 整数
67
+ stage.cast_members #=> ["筧利夫", "諏訪珠理", ...] 読点区切り → 配列
68
+ stage.min_price #=> 3000 "3,000円 ~ 9,500円" → 最小値
69
+ stage.max_price #=> 9500 "3,000円 ~ 9,500円" → 最大値
70
+ ```
71
+
72
+ ### 設定
73
+
74
+ ```ruby
75
+ # config/initializers/corich_stage.rb
76
+ CorichStage.configure do |config|
77
+ config.user_agent = "MyApp/1.0 (+https://example.com)"
78
+ config.request_interval = 2.0 # リクエスト間隔(秒)
79
+ config.timeout = 30 # タイムアウト(秒)
80
+ config.max_retries = 3 # リトライ回数
81
+ end
82
+ ```
83
+
84
+ Rails環境では `CorichStage.logger` に `Rails.logger` が自動設定されます。
85
+
86
+ ## Rails連携の例
87
+
88
+ ```ruby
89
+ # app/jobs/fetch_stages_job.rb
90
+ class FetchStagesJob < ApplicationJob
91
+ queue_as :default
92
+ limits_concurrency to: 1, key: "corich_fetch"
93
+
94
+ def perform
95
+ summaries = CorichStage.search(max_pages: 10)
96
+ summaries.each do |summary|
97
+ next if Performance.exists?(corich_id: summary.stage_id)
98
+ FetchStageDetailJob.perform_later(summary.stage_id)
99
+ end
100
+ end
101
+ end
102
+ ```
103
+
104
+ ## 注意事項
105
+
106
+ - 本gemは [CoRich舞台芸術](https://stage.corich.jp) の公式APIではなく、Webスクレイピングにより情報を取得します
107
+ - サイトへの過度なアクセスを避けるため、`request_interval` を適切に設定してください(デフォルト: 1秒)
108
+ - サイトの構造変更により動作しなくなる場合があります
109
+ - サイト運営者から要請があった場合は利用を停止してください
110
+
111
+ ## 依存
112
+
113
+ - Ruby >= 3.2
114
+ - Nokogiri
115
+ - net-http
116
+
117
+ ## ライセンス
118
+
119
+ MIT
@@ -0,0 +1,69 @@
1
+ module CorichStage
2
+ class Client
3
+ MAX_REDIRECTS = 5
4
+
5
+ def initialize
6
+ @last_request_at = nil
7
+ end
8
+
9
+ def get(path, params: {})
10
+ throttle!
11
+ uri = build_uri(path, params)
12
+
13
+ response = perform_request(uri)
14
+ @last_request_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
15
+
16
+ response.body.dup.force_encoding("UTF-8")
17
+ end
18
+
19
+ private
20
+
21
+ def headers
22
+ {
23
+ "User-Agent" => CorichStage.user_agent,
24
+ "Accept-Language" => "ja,en-US;q=0.9,en;q=0.8",
25
+ "Accept" => "text/html,application/xhtml+xml"
26
+ }
27
+ end
28
+
29
+ def build_uri(path, params)
30
+ uri = URI.join(CorichStage::BASE_URL, path)
31
+ uri.query = URI.encode_www_form(params) unless params.empty?
32
+ uri
33
+ end
34
+
35
+ def perform_request(uri, attempt: 0, redirects: 0)
36
+ http = Net::HTTP.new(uri.host, uri.port)
37
+ http.use_ssl = true
38
+ http.open_timeout = CorichStage.timeout
39
+ http.read_timeout = CorichStage.timeout
40
+
41
+ request = Net::HTTP::Get.new(uri, headers)
42
+ response = http.request(request)
43
+
44
+ case response
45
+ when Net::HTTPSuccess
46
+ response
47
+ when Net::HTTPRedirection
48
+ raise RequestError, "Too many redirects" if redirects >= MAX_REDIRECTS
49
+ perform_request(URI(response["Location"]), attempt: attempt, redirects: redirects + 1)
50
+ when Net::HTTPTooManyRequests, Net::HTTPServiceUnavailable
51
+ raise RequestError, "#{response.code} after #{attempt} retries: #{response.message}" if attempt >= CorichStage.max_retries
52
+ sleep_time = (response["Retry-After"]&.to_i || 5) * (attempt + 1)
53
+ CorichStage.logger&.warn("[CorichStage] #{response.code} - retry #{attempt + 1}/#{CorichStage.max_retries}, sleeping #{sleep_time}s")
54
+ sleep(sleep_time)
55
+ perform_request(uri, attempt: attempt + 1, redirects: redirects)
56
+ else
57
+ raise RequestError, "HTTP #{response.code}: #{response.message}"
58
+ end
59
+ end
60
+
61
+ def throttle!
62
+ return unless @last_request_at
63
+
64
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @last_request_at
65
+ remaining = CorichStage.request_interval - elapsed
66
+ sleep(remaining) if remaining > 0
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,128 @@
1
+ module CorichStage
2
+ class DetailParser
3
+ PERIOD_RE = /\d{4}\/\d{2}\/\d{2}\s*\([^)]+\)\s*~\s*\d{4}\/\d{2}\/\d{2}\s*\([^)]+\)/
4
+ STATUS_RE = /上演中|予約受付中|もうすぐ開幕|もうすぐ閉幕|終演/
5
+
6
+ SECTION_LABELS = %w[
7
+ スタッフ 出演 脚本 演出 料金(1枚あたり)
8
+ 公式/劇場サイト タイムテーブル その他注意事項
9
+ ].to_set.freeze
10
+
11
+ def initialize(html, stage_id:)
12
+ @doc = Nokogiri::HTML(html)
13
+ @stage_id = stage_id
14
+ @lines = extract_lines
15
+ end
16
+
17
+ def parse
18
+ Stage.new(
19
+ stage_id: @stage_id,
20
+ url: "#{CorichStage::BASE_URL}/stage/#{@stage_id}",
21
+ title: extract_title,
22
+ company: extract_company,
23
+ venue: extract_labeled_value("劇場"),
24
+ prefecture: nil,
25
+ period: combined_text[PERIOD_RE],
26
+ status: extract_status,
27
+ duration: extract_inline_value("上演時間:"),
28
+ prices: extract_labeled_value("料金(1枚あたり)"),
29
+ description: extract_description,
30
+ cast: extract_labeled_value("出演"),
31
+ staff: extract_labeled_value("スタッフ"),
32
+ director_name: extract_labeled_value("演出"),
33
+ playwright_name: extract_labeled_value("脚本"),
34
+ official_site: extract_official_site
35
+ )
36
+ end
37
+
38
+ private
39
+
40
+ def extract_lines
41
+ @doc.text.split("\n").map { _1.gsub(/\s+/, " ").strip }.reject(&:empty?)
42
+ end
43
+
44
+ def combined_text
45
+ @combined_text ||= @lines.join("\n")
46
+ end
47
+
48
+ def extract_title
49
+ @doc.css("h1").each do |h1|
50
+ text = h1.text.gsub(/\s+/, " ").strip
51
+ return text if !text.empty? && !text.include?("CoRich舞台芸術")
52
+ end
53
+
54
+ title_tag = @doc.at_css("title")
55
+ return title_tag.text.split("|").first.strip if title_tag
56
+
57
+ ""
58
+ end
59
+
60
+ def extract_company
61
+ troupe_link = @doc.at_css('a[href*="/troupe/"]')
62
+ troupe_link&.text&.strip
63
+ end
64
+
65
+ def extract_status
66
+ @lines.each do |line|
67
+ next unless PERIOD_RE.match?(line)
68
+ status = line[STATUS_RE]
69
+ return status if status
70
+ end
71
+
72
+ @lines.each do |line|
73
+ status = line[STATUS_RE]
74
+ return status if status
75
+ end
76
+
77
+ nil
78
+ end
79
+
80
+ def extract_labeled_value(label)
81
+ @lines.each_with_index do |line, i|
82
+ if line == label && i + 1 < @lines.size
83
+ return @lines[i + 1]
84
+ end
85
+ if line.start_with?("#{label} ")
86
+ return line.delete_prefix("#{label} ").strip
87
+ end
88
+ end
89
+ nil
90
+ end
91
+
92
+ def extract_inline_value(prefix)
93
+ @lines.each_with_index do |line, i|
94
+ if line.start_with?(prefix)
95
+ remainder = line.delete_prefix(prefix).strip
96
+ return remainder unless remainder.empty?
97
+ return @lines[i + 1] if i + 1 < @lines.size
98
+ end
99
+ end
100
+ nil
101
+ end
102
+
103
+ def extract_description
104
+ @lines.each_with_index do |line, i|
105
+ if line.start_with?("説明 ")
106
+ return line.delete_prefix("説明 ").strip
107
+ end
108
+ if line == "説明"
109
+ chunks = @lines[(i + 1)..].take_while { !SECTION_LABELS.include?(_1) }
110
+ return chunks.join(" ").gsub(/\s+/, " ").strip if chunks.any?
111
+ end
112
+ end
113
+ nil
114
+ end
115
+
116
+ def extract_official_site
117
+ %w[公式サイト: 公式サイト 公式/劇場サイト].each do |label|
118
+ node = @doc.at_xpath("//*[contains(text(), '#{label}')]")
119
+ next unless node
120
+ anchor = node.at_css("~ a[href], a[href]") || node.parent&.at_css("a[href]")
121
+ next unless anchor
122
+ href = anchor["href"].strip
123
+ return href if href.start_with?("http") && !href.include?("ticket.corich.jp")
124
+ end
125
+ nil
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,5 @@
1
+ module CorichStage
2
+ class Error < StandardError; end
3
+ class RequestError < Error; end
4
+ class ParseError < Error; end
5
+ end
@@ -0,0 +1,68 @@
1
+ module CorichStage
2
+ class ListingParser
3
+ STAGE_HREF_RE = %r{\A/stage/(\d+)\z}
4
+ PERIOD_RE = /\d{4}\/\d{2}\/\d{2}\s*\([^)]+\)\s*~\s*\d{4}\/\d{2}\/\d{2}\s*\([^)]+\)/
5
+ PRICE_RE = /\d[\d,]*円\s*~\s*\d[\d,]*円/
6
+ PREFECTURE_RE = /\A([^)]+)\z/
7
+ STATUS_RE = /上演中|予約受付中|もうすぐ開幕|もうすぐ閉幕|終演/
8
+
9
+ def initialize(html)
10
+ @doc = Nokogiri::HTML(html)
11
+ end
12
+
13
+ def parse
14
+ seen = Set.new
15
+ summaries = []
16
+
17
+ @doc.css("a[href]").each do |anchor|
18
+ href = anchor["href"]
19
+ match = STAGE_HREF_RE.match(href)
20
+ next unless match
21
+
22
+ stage_id = match[1]
23
+ next if seen.include?(stage_id)
24
+
25
+ parts = extract_parts(anchor)
26
+ next if parts.empty?
27
+
28
+ raw_text = parts.join(" ")
29
+ period = raw_text[PERIOD_RE]
30
+ next unless period
31
+
32
+ seen.add(stage_id)
33
+ summaries << build_summary(stage_id, href, parts, raw_text, period)
34
+ end
35
+
36
+ summaries
37
+ end
38
+
39
+ private
40
+
41
+ def extract_parts(anchor)
42
+ anchor.text.split("\n").map { _1.gsub(/\s+/, " ").strip }.reject(&:empty?)
43
+ end
44
+
45
+ def build_summary(stage_id, href, parts, raw_text, period)
46
+ prefecture = parts.find { PREFECTURE_RE.match?(_1) }
47
+ venue = extract_venue(parts, prefecture)
48
+
49
+ StageSummary.new(
50
+ stage_id: stage_id,
51
+ url: "#{CorichStage::BASE_URL}#{href}",
52
+ title: parts.first,
53
+ venue: venue,
54
+ prefecture: prefecture,
55
+ period: period,
56
+ price_range: raw_text[PRICE_RE],
57
+ status: raw_text[STATUS_RE]
58
+ )
59
+ end
60
+
61
+ def extract_venue(parts, prefecture)
62
+ return nil unless prefecture
63
+ idx = parts.index(prefecture)
64
+ return nil unless idx && idx > 0
65
+ parts[idx - 1]
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ module CorichStage
2
+ class Railtie < Rails::Railtie
3
+ initializer "corich_stage.configure" do
4
+ CorichStage.logger = Rails.logger
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,59 @@
1
+ module CorichStage
2
+ class Search
3
+ TOKYO_AREA_ID = 3
4
+ PER_PAGE = 20
5
+
6
+ def initialize(area_id: TOKYO_AREA_ID, sort: "start", days_ahead: 90, max_pages: nil, date: Date.today)
7
+ @area_id = area_id
8
+ @sort = sort
9
+ @days_ahead = days_ahead
10
+ @max_pages = max_pages
11
+ @date = date
12
+ @client = Client.new
13
+ end
14
+
15
+ def results
16
+ summaries = []
17
+ page = 1
18
+
19
+ loop do
20
+ html = @client.get("/stage/search", params: search_params(page))
21
+ batch = ListingParser.new(html).parse
22
+
23
+ break if batch.empty?
24
+
25
+ summaries.concat(batch)
26
+ page += 1
27
+
28
+ break if @max_pages && page > @max_pages
29
+ break if batch.size < PER_PAGE
30
+ end
31
+
32
+ filter_by_date(summaries)
33
+ end
34
+
35
+ def page(number)
36
+ html = @client.get("/stage/search", params: search_params(number))
37
+ ListingParser.new(html).parse
38
+ end
39
+
40
+ private
41
+
42
+ def search_params(page)
43
+ {
44
+ "stage_search[area_id]" => @area_id,
45
+ "stage_search[scope]" => "firing",
46
+ "sort" => @sort,
47
+ "page" => page,
48
+ "freeword_type" => "all"
49
+ }
50
+ end
51
+
52
+ def filter_by_date(summaries)
53
+ return summaries unless @days_ahead
54
+
55
+ cutoff = @date + @days_ahead
56
+ summaries.select { _1.end_date.nil? || _1.end_date <= cutoff }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,56 @@
1
+ module CorichStage
2
+ Stage = Data.define(
3
+ :stage_id,
4
+ :url,
5
+ :title,
6
+ :company,
7
+ :venue,
8
+ :prefecture,
9
+ :period,
10
+ :status,
11
+ :duration,
12
+ :prices,
13
+ :description,
14
+ :cast,
15
+ :staff,
16
+ :director_name,
17
+ :playwright_name,
18
+ :official_site
19
+ ) do
20
+ DURATION_RE = /(\d+)\s*時間\s*(\d+)?\s*分?|約?(\d+)\s*分/
21
+
22
+ def duration_minutes
23
+ return nil unless duration
24
+ match = duration.match(DURATION_RE)
25
+ return nil unless match
26
+
27
+ if match[1] # N時間M分
28
+ match[1].to_i * 60 + (match[2]&.to_i || 0)
29
+ else # N分
30
+ match[3].to_i
31
+ end
32
+ end
33
+
34
+ def cast_members
35
+ return [] unless cast
36
+ cast.split(/[、,]/).map(&:strip).reject(&:empty?)
37
+ end
38
+
39
+ def min_price
40
+ extract_price(:min)
41
+ end
42
+
43
+ def max_price
44
+ extract_price(:max)
45
+ end
46
+
47
+ private
48
+
49
+ def extract_price(type)
50
+ return nil unless prices
51
+ numbers = prices.scan(/[\d,]+(?=円)/).map { _1.delete(",").to_i }
52
+ return nil if numbers.empty?
53
+ type == :min ? numbers.min : numbers.max
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ module CorichStage
2
+ StageSummary = Data.define(
3
+ :stage_id,
4
+ :url,
5
+ :title,
6
+ :venue,
7
+ :prefecture,
8
+ :period,
9
+ :price_range,
10
+ :status
11
+ ) do
12
+ def detail_url
13
+ "#{CorichStage::BASE_URL}/stage/#{stage_id}"
14
+ end
15
+
16
+ def end_date
17
+ return nil unless period
18
+ match = period.match(%r{~\s*(\d{4})/(\d{2})/(\d{2})})
19
+ return nil unless match
20
+ Date.new(match[1].to_i, match[2].to_i, match[3].to_i)
21
+ end
22
+
23
+ def start_date
24
+ return nil unless period
25
+ match = period.match(%r{(\d{4})/(\d{2})/(\d{2})})
26
+ return nil unless match
27
+ Date.new(match[1].to_i, match[2].to_i, match[3].to_i)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ require "uri"
2
+ require "net/http"
3
+ require "nokogiri"
4
+ require "set"
5
+ require "date"
6
+
7
+ require_relative "corich_stage/error"
8
+ require_relative "corich_stage/stage_summary"
9
+ require_relative "corich_stage/stage"
10
+ require_relative "corich_stage/client"
11
+ require_relative "corich_stage/listing_parser"
12
+ require_relative "corich_stage/detail_parser"
13
+ require_relative "corich_stage/search"
14
+
15
+ module CorichStage
16
+ BASE_URL = "https://stage.corich.jp"
17
+
18
+ class << self
19
+ attr_accessor :user_agent, :request_interval, :timeout, :max_retries, :logger
20
+ end
21
+
22
+ self.user_agent = "CorichStage/0.1 (+https://github.com/ryu/corich_stage)"
23
+ self.request_interval = 1.0
24
+ self.timeout = 20
25
+ self.max_retries = 3
26
+ self.logger = nil
27
+
28
+ def self.configure
29
+ yield self
30
+ end
31
+
32
+ def self.search(**params)
33
+ Search.new(**params).results
34
+ end
35
+
36
+ def self.fetch(stage_id)
37
+ client = Client.new
38
+ html = client.get("/stage/#{stage_id}")
39
+ DetailParser.new(html, stage_id: stage_id).parse
40
+ end
41
+ end
42
+
43
+ require_relative "corich_stage/railtie" if defined?(Rails::Railtie)
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: corich_stage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryu Yamamoto
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: nokogiri
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.16'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.16'
26
+ - !ruby/object:Gem::Dependency
27
+ name: net-http
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '13.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '13.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: webmock
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ description: Ruby library for scraping performance information from CoRich Stage (stage.corich.jp).
83
+ Supports searching listings and fetching detailed show data with built-in rate limiting.
84
+ email:
85
+ - ryu.yamamoto@icloud.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - LICENSE
91
+ - README.md
92
+ - lib/corich_stage.rb
93
+ - lib/corich_stage/client.rb
94
+ - lib/corich_stage/detail_parser.rb
95
+ - lib/corich_stage/error.rb
96
+ - lib/corich_stage/listing_parser.rb
97
+ - lib/corich_stage/railtie.rb
98
+ - lib/corich_stage/search.rb
99
+ - lib/corich_stage/stage.rb
100
+ - lib/corich_stage/stage_summary.rb
101
+ homepage: https://github.com/ryu/corich_stage
102
+ licenses:
103
+ - MIT
104
+ metadata:
105
+ homepage_uri: https://github.com/ryu/corich_stage
106
+ source_code_uri: https://github.com/ryu/corich_stage
107
+ documentation_uri: https://github.com/ryu/corich_stage#readme
108
+ bug_tracker_uri: https://github.com/ryu/corich_stage/issues
109
+ rubygems_mfa_required: 'true'
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '3.2'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 4.0.6
125
+ specification_version: 4
126
+ summary: Scraper for CoRich Stage (stage.corich.jp)
127
+ test_files: []