hanreki 1.2.0 → 4.2.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 +5 -5
- data/README.md +22 -0
- data/hanreki.gemspec +4 -4
- data/lib/hanreki/cli.rb +23 -9
- data/lib/hanreki/event.rb +28 -15
- data/lib/hanreki/exceptions.rb +8 -0
- data/lib/hanreki/i_calendar.rb +2 -2
- data/lib/hanreki/schedule.rb +5 -13
- data/lib/hanreki/version.rb +1 -1
- metadata +17 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 944f39bf167421f37e9bb814289d58b77a791695cae547cca3d4afd7acd9d2b5
|
4
|
+
data.tar.gz: ca7b46cc65c16e5fe7c61ff6e4739d4a7d8194b64b35a767f312520ca987abfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b8d3882ee6bb4186b9d3c5e2acc7d43e5914bc9590bc686707526e247d809e43a90a69a3b35712dc509a304df58881be1386db997e48769bf328792d3b50a2
|
7
|
+
data.tar.gz: 0b406751aef3e864deba94e983811cf8e174cd75db217ecfc8b31ddc1e06cc339c40affcbdccf5e29f90e67cd753be4d188ea454ac37eaff9b01a56ebbad3aaa
|
data/README.md
CHANGED
@@ -5,6 +5,11 @@
|
|
5
5
|
|
6
6
|
Simple schedule manager for [CAMPHOR-](https://camph.net/)
|
7
7
|
|
8
|
+
## Features
|
9
|
+
- Manage public & private schedules
|
10
|
+
- Manage events using simple CSV master files
|
11
|
+
- Convert master files to iCal and JSON files
|
12
|
+
|
8
13
|
## Installation
|
9
14
|
### Gem
|
10
15
|
Install hanreki with gem command:
|
@@ -27,6 +32,23 @@ And then execute:
|
|
27
32
|
## Usage
|
28
33
|
Run `hanreki help` or `bundle exec hanreki help`.
|
29
34
|
|
35
|
+
### Create a master file
|
36
|
+
`hanreki blank` generates a master file for the next month.
|
37
|
+
|
38
|
+
### Sync
|
39
|
+
`hanreki sync` generates iCal and JSON files from master files.
|
40
|
+
|
41
|
+
### Edit
|
42
|
+
`hanreki edit` opens a editor and validates master files.
|
43
|
+
Hanreki chooses the editor in the following order:
|
44
|
+
|
45
|
+
1. Editor specified by the environment variable: `CAMPHOR_SCHEDULE_EDITOR`
|
46
|
+
2. Editor specified by the environment variable: `EDITOR`
|
47
|
+
3. `vi`
|
48
|
+
|
49
|
+
### Validation
|
50
|
+
`hanreki validate` validates master files.
|
51
|
+
|
30
52
|
## Development
|
31
53
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
32
54
|
|
data/hanreki.gemspec
CHANGED
@@ -24,13 +24,13 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
|
-
spec.required_ruby_version = '>= 2.
|
27
|
+
spec.required_ruby_version = '>= 2.2.0'
|
28
28
|
|
29
|
-
spec.add_dependency 'thor', '
|
29
|
+
spec.add_dependency 'thor', '>= 0.19', '< 2.0'
|
30
30
|
spec.add_dependency 'icalendar', '~> 2.3'
|
31
31
|
spec.add_dependency 'json-schema', '~> 2.7'
|
32
32
|
|
33
|
-
spec.add_development_dependency 'bundler', '~> 1
|
34
|
-
spec.add_development_dependency 'rake', '~>
|
33
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
34
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
35
35
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
36
36
|
end
|
data/lib/hanreki/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'thor'
|
3
|
+
require 'hanreki/exceptions'
|
3
4
|
require 'hanreki/schedule'
|
4
5
|
require 'hanreki/time_util'
|
5
6
|
require 'hanreki/version'
|
@@ -29,23 +30,18 @@ module Hanreki
|
|
29
30
|
validate
|
30
31
|
end
|
31
32
|
|
32
|
-
desc 'sync', 'Sync iCal
|
33
|
+
desc 'sync', 'Sync iCal and JSON'
|
33
34
|
def sync
|
34
|
-
schedule =
|
35
|
-
schedule.
|
35
|
+
schedule = load_schedule
|
36
|
+
schedule.sort_by_date!
|
36
37
|
schedule.out_ical
|
37
38
|
schedule.out_json
|
38
|
-
schedule.out_jsonp
|
39
39
|
end
|
40
40
|
|
41
41
|
desc 'validate', 'Validate master files'
|
42
42
|
def validate
|
43
43
|
schedule = Schedule.new
|
44
|
-
|
45
|
-
schedule.load_master_files
|
46
|
-
rescue => e
|
47
|
-
raise "validation error: #{e}"
|
48
|
-
end
|
44
|
+
schedule = load_schedule
|
49
45
|
end
|
50
46
|
|
51
47
|
desc 'version', 'Show the version information'
|
@@ -56,6 +52,24 @@ module Hanreki
|
|
56
52
|
|
57
53
|
private
|
58
54
|
|
55
|
+
def load_schedule()
|
56
|
+
schedule = Schedule.new
|
57
|
+
begin
|
58
|
+
schedule.load_master_files
|
59
|
+
rescue ValidationError => e
|
60
|
+
message = 'validation error'
|
61
|
+
if e.event
|
62
|
+
message += " at line #{e.event.line_number}" if e.event.line_number
|
63
|
+
message += " in #{e.event.filename}" if e.event.filename
|
64
|
+
message += "\n#{e.event.row.to_s.strip}" if e.event.row
|
65
|
+
end
|
66
|
+
message += "\n#{e}"
|
67
|
+
puts message
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
schedule
|
71
|
+
end
|
72
|
+
|
59
73
|
# Parse a string (YYYYMM) in options[:date] and returns [YYYY, MM]
|
60
74
|
def parse_month_in_options(options, default = nil)
|
61
75
|
date = options[:date]
|
data/lib/hanreki/event.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'icalendar'
|
2
|
+
require 'hanreki/exceptions'
|
2
3
|
require 'hanreki/time_util'
|
3
4
|
|
4
5
|
# Event of CAMPHOR- Schedule
|
5
6
|
class Event
|
6
7
|
using ExtendTime
|
7
8
|
DOWS = %w(日 月 火 水 木 金 土)
|
9
|
+
attr_accessor :filename, :line_number, :row
|
8
10
|
attr_accessor :start, :end
|
9
11
|
attr_accessor :public_summary, :private_summary
|
10
12
|
attr_accessor :url
|
@@ -23,29 +25,34 @@ class Event
|
|
23
25
|
# month: String (e.g. 201510)
|
24
26
|
# line: CSV::Row
|
25
27
|
# (eg. [01, 水, 15:00, 20:00, "HOUSE 開館", "HOUSE 当番 @ivstivs", https://camph.net])
|
26
|
-
def self.from_master(month, line)
|
27
|
-
event = Event.new({
|
28
|
+
def self.from_master(filename, line_number, month, line)
|
29
|
+
event = Event.new({
|
30
|
+
row: line,
|
31
|
+
filename: filename,
|
32
|
+
line_number: line_number,
|
33
|
+
})
|
28
34
|
first_day = Date.parse("#{month}01")
|
35
|
+
raise ValidationError.new(event), 'invalid number of columns' unless line.length == 7
|
29
36
|
day, dow, hour_start, hour_end, public_summary, private_summary, url = line.fields.map { |c| c.to_s.strip }
|
30
37
|
# Zero-fill (eg. 1 -> 01, 02 -> 02)
|
31
38
|
day = day.rjust(2, "0")
|
32
|
-
raise
|
33
|
-
raise
|
39
|
+
raise ValidationError.new(event), 'invalid day' unless day.length == 2
|
40
|
+
raise ValidationError.new(event), 'invalid day' unless (first_day...first_day.next_month).include?(Date.parse("#{month}#{day}"))
|
34
41
|
event.start = Time.parse("#{month}#{day} #{hour_start} +09:00").getlocal("+09:00")
|
35
42
|
event.end = Time.parse("#{month}#{day} #{hour_end} +09:00").getlocal("+09:00")
|
36
43
|
event.public_summary = public_summary unless public_summary.empty?
|
37
44
|
event.private_summary = private_summary unless private_summary.empty?
|
38
45
|
event.url = url unless url.empty?
|
39
46
|
# 曜日はインスタンス変数に保持しないのでここでチェックする
|
40
|
-
raise
|
41
|
-
raise
|
47
|
+
raise ValidationError.new(event), 'invalid day of the week' unless DOWS.include? dow
|
48
|
+
raise ValidationError.new(event), 'invalid day of the week' unless DOWS[event.start.wday] == dow
|
42
49
|
event.validate
|
43
50
|
event
|
44
51
|
end
|
45
52
|
|
46
53
|
def to_h(type, time_type = :time)
|
47
|
-
fail
|
48
|
-
fail
|
54
|
+
fail ValidationError.new(self), 'invalid type' unless [:public, :private].include?(type)
|
55
|
+
fail ValidationError.new(self), 'invalid time_type' unless [:time, :string].include?(time_type)
|
49
56
|
hash = {
|
50
57
|
start: @start,
|
51
58
|
end: @end,
|
@@ -82,35 +89,41 @@ class Event
|
|
82
89
|
# イベントのバリデーションを行う
|
83
90
|
# バリデーションに成功した場合は true を返し, 失敗した場合は例外を送出する
|
84
91
|
def validate
|
85
|
-
raise
|
92
|
+
raise ValidationError.new(self), 'invalid start & end' if @start > @end
|
86
93
|
|
87
94
|
if @public_summary.nil? and @private_summary.nil?
|
88
|
-
raise
|
95
|
+
raise ValidationError.new(self), 'both summaries are not set'
|
89
96
|
end
|
90
97
|
|
91
98
|
if @public_summary == 'Open'
|
92
99
|
if @start == @end
|
93
|
-
raise
|
100
|
+
raise ValidationError.new(self), '"open" event should have duration'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if @public_summary == 'Online Open'
|
105
|
+
if @start == @end
|
106
|
+
raise ValidationError.new(self), '"online open" event should have duration'
|
94
107
|
end
|
95
108
|
end
|
96
109
|
|
97
110
|
if @private_summary == 'Closed'
|
98
111
|
if not @public_summary.nil?
|
99
|
-
raise
|
112
|
+
raise ValidationError.new(self), 'invalid public summary for a closed event'
|
100
113
|
end
|
101
114
|
|
102
115
|
if not @start.is_midnight_in_jst
|
103
|
-
raise
|
116
|
+
raise ValidationError.new(self), 'start must be 0:00 for a closed event'
|
104
117
|
end
|
105
118
|
|
106
119
|
if not @end.is_midnight_in_jst
|
107
|
-
raise
|
120
|
+
raise ValidationError.new(self), 'end must be 0:00 for a closed event'
|
108
121
|
end
|
109
122
|
end
|
110
123
|
|
111
124
|
unless @url.nil?
|
112
125
|
unless @url.start_with?('http://') or @url.start_with?('https://')
|
113
|
-
raise
|
126
|
+
raise ValidationError.new(self), 'invalid url scheme'
|
114
127
|
end
|
115
128
|
end
|
116
129
|
|
data/lib/hanreki/i_calendar.rb
CHANGED
@@ -19,8 +19,8 @@ class ICalendar
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def set_event(event, type)
|
22
|
-
fail
|
23
|
-
fail
|
22
|
+
fail ValidationError.new(event), 'invalid date' unless event.start && event.end
|
23
|
+
fail ValidationError.new(event), 'invalid type' unless [:public, :private].include?(type)
|
24
24
|
@calendar.event do |e|
|
25
25
|
e.dtstart = event.start
|
26
26
|
e.dtend = event.end
|
data/lib/hanreki/schedule.rb
CHANGED
@@ -13,8 +13,6 @@ class Schedule
|
|
13
13
|
ICAL_PRIVATE_PATH = 'ical/camphor_private_events.ics'
|
14
14
|
JSON_PUBLIC_PATH = 'json/camphor_public_events.json'
|
15
15
|
JSON_PRIVATE_PATH = 'json/camphor_private_events.json'
|
16
|
-
JSONP_PUBLIC_PATH = 'jsonp/camphor_public_events.js'
|
17
|
-
JSONP_PRIVATE_PATH = 'jsonp/camphor_private_events.js'
|
18
16
|
JSON_SCHEMA_PATH = File.expand_path('../schema.json', __FILE__)
|
19
17
|
|
20
18
|
def initialize
|
@@ -35,7 +33,7 @@ class Schedule
|
|
35
33
|
@events = Dir.glob('master/*.csv').flat_map do |f|
|
36
34
|
month = f.match(/master\/(\d+).csv/)[1]
|
37
35
|
CSV.open(f, headers: true) do |csv|
|
38
|
-
csv.map { |
|
36
|
+
csv.map { |row| Event.from_master(f, $., month, row) }
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
@@ -64,16 +62,6 @@ class Schedule
|
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
# Output private and public JSONP calendar files
|
68
|
-
def out_jsonp(callback = 'callback')
|
69
|
-
File.open(JSONP_PUBLIC_PATH, 'w') do |f|
|
70
|
-
f.write("#{callback}(#{events_to_json(public_events, :public)});")
|
71
|
-
end
|
72
|
-
File.open(JSONP_PRIVATE_PATH, 'w') do |f|
|
73
|
-
f.write("#{callback}(#{events_to_json(private_events, :private)});")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
65
|
# Output master file
|
78
66
|
def out_master
|
79
67
|
CSV.open(
|
@@ -88,6 +76,10 @@ class Schedule
|
|
88
76
|
File.exists? file_path
|
89
77
|
end
|
90
78
|
|
79
|
+
def sort_by_date!
|
80
|
+
@events.sort_by! { |e| [e.start, e.end] }
|
81
|
+
end
|
82
|
+
|
91
83
|
private
|
92
84
|
|
93
85
|
def file_path
|
data/lib/hanreki/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanreki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CAMPHOR-
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.19'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0.19'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: icalendar
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,28 +64,28 @@ dependencies:
|
|
58
64
|
requirements:
|
59
65
|
- - "~>"
|
60
66
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1
|
67
|
+
version: '2.1'
|
62
68
|
type: :development
|
63
69
|
prerelease: false
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
65
71
|
requirements:
|
66
72
|
- - "~>"
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1
|
74
|
+
version: '2.1'
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rake
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
72
78
|
requirements:
|
73
79
|
- - "~>"
|
74
80
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
81
|
+
version: '13.0'
|
76
82
|
type: :development
|
77
83
|
prerelease: false
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
79
85
|
requirements:
|
80
86
|
- - "~>"
|
81
87
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
88
|
+
version: '13.0'
|
83
89
|
- !ruby/object:Gem::Dependency
|
84
90
|
name: rspec
|
85
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,6 +116,7 @@ files:
|
|
110
116
|
- lib/hanreki.rb
|
111
117
|
- lib/hanreki/cli.rb
|
112
118
|
- lib/hanreki/event.rb
|
119
|
+
- lib/hanreki/exceptions.rb
|
113
120
|
- lib/hanreki/i_calendar.rb
|
114
121
|
- lib/hanreki/schedule.rb
|
115
122
|
- lib/hanreki/schema.json
|
@@ -127,15 +134,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
134
|
requirements:
|
128
135
|
- - ">="
|
129
136
|
- !ruby/object:Gem::Version
|
130
|
-
version: 2.
|
137
|
+
version: 2.2.0
|
131
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
139
|
requirements:
|
133
140
|
- - ">="
|
134
141
|
- !ruby/object:Gem::Version
|
135
142
|
version: '0'
|
136
143
|
requirements: []
|
137
|
-
|
138
|
-
rubygems_version: 2.6.8
|
144
|
+
rubygems_version: 3.0.3
|
139
145
|
signing_key:
|
140
146
|
specification_version: 4
|
141
147
|
summary: Simple schedule manager for CAMPHOR-
|