hanreki 1.2.0 → 4.2.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
- SHA1:
3
- metadata.gz: a867b87334a1a1be5954d74b9059cd465651f1a5
4
- data.tar.gz: 2961b20754273404809b8c9f8f1d2d789edfb879
2
+ SHA256:
3
+ metadata.gz: 944f39bf167421f37e9bb814289d58b77a791695cae547cca3d4afd7acd9d2b5
4
+ data.tar.gz: ca7b46cc65c16e5fe7c61ff6e4739d4a7d8194b64b35a767f312520ca987abfb
5
5
  SHA512:
6
- metadata.gz: a04b6f1fe15222d4de38772121cfe025a0df77008a58a726e09cec72bf0f2b4fa3650ac7ec4e4ef1f4ef1eca17d850bd8889369c920bab1dd332114a15d44709
7
- data.tar.gz: 8579bada5beea05a9b7cf71eea9e2e423a456425430e28034dc77e2c19e3a0f36cb2fba1db85351ac6b097a9bca8ec536c53036b288d96e2f466eb3d6ffed9e7
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.1.0'
27
+ spec.required_ruby_version = '>= 2.2.0'
28
28
 
29
- spec.add_dependency 'thor', '~> 0.19'
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.12'
34
- spec.add_development_dependency 'rake', '~> 12.0'
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, JSON, and JSONP'
33
+ desc 'sync', 'Sync iCal and JSON'
33
34
  def sync
34
- schedule = Schedule.new
35
- schedule.load_master_files
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
- begin
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 ArgumentError, 'invalid day' unless day.length == 2
33
- raise ArgumentError, 'invalid day' unless (first_day...first_day.next_month).include?(Date.parse("#{month}#{day}"))
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 ArgumentError, 'invalid day of the week' unless DOWS.include? dow
41
- raise ArgumentError, 'invalid day of the week' unless DOWS[event.start.wday] == dow
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 ArgumentError, 'Invalid type' unless [:public, :private].include?(type)
48
- fail ArgumentError, 'Invalid time_type' unless [:time, :string].include?(time_type)
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 ArgumentError, 'invalid start & end' if @start > @end
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 ArgumentError, 'both summaries are not set'
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 ArgumentError, '"open" event should have duration'
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 ArgumentError, 'invalid public summary for a closed event'
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 ArgumentError, 'start must be 0:00 for a closed event'
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 ArgumentError, 'end must be 0:00 for a closed event'
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 ArgumentError, 'invalid url scheme'
126
+ raise ValidationError.new(self), 'invalid url scheme'
114
127
  end
115
128
  end
116
129
 
@@ -0,0 +1,8 @@
1
+ class ValidationError < StandardError
2
+ attr_reader :event
3
+
4
+ def initialize(event)
5
+ super
6
+ @event = event
7
+ end
8
+ end
@@ -19,8 +19,8 @@ class ICalendar
19
19
  end
20
20
 
21
21
  def set_event(event, type)
22
- fail ArgumentError, 'Invalid date' unless event.start && event.end
23
- fail ArgumentError, 'Invalid type' unless [:public, :private].include?(type)
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
@@ -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 { |line| Event.from_master(month, line) }
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
@@ -1,3 +1,3 @@
1
1
  module Hanreki
2
- VERSION = '1.2.0'
2
+ VERSION = '4.2.0'
3
3
  end
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: 1.2.0
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: 2017-05-03 00:00:00.000000000 Z
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.12'
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.12'
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: '12.0'
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: '12.0'
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.1.0
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
- rubyforge_project:
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-