hijiri 0.0.1

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
+ SHA1:
3
+ metadata.gz: e2e82a154e92909d70553889350dc0b5d4b74b34
4
+ data.tar.gz: c5dd355694a01a85d6e5a987da5ca753e40438c4
5
+ SHA512:
6
+ metadata.gz: 067c9f8552c2af979607ba035380241d3ae8c0866fd9e7326c2e3d25419ebc3c648d94a789d27026d4e11fdecbb17049dd0680ee1ee50bb9c255fc6d4aa1b099
7
+ data.tar.gz: e5bd3813dd76a434cc5c5db3786329ccffc202e0ada48bd4af1cbd912df2016fae53042382b3117f3df39c92b83fe358fbe9a63d135253b6de3dc4179127c0b6
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hijiri.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 kkosuge
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Hijiri
2
+
3
+ 日本語の文中に含まれる時刻表現をパースします。
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'hijiri'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install hijiri
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'hijiri'
25
+
26
+ hijiri = Hijiri.parse("1977年8月15日11時42分33秒")
27
+ p hijiri.results.first.datetime #=> 1977-08-15 11:42:33 +0900
28
+
29
+ hijiri = Hijiri.parse("忘れない10年後の8月また出会えるのを…")
30
+ p hijiri.results.first.datetime #=> 2024-08-01 00:00:00 +0900
31
+
32
+ hijiri = Hijiri.parse("あうあうあー15分後に…")
33
+ p hijiri.results.first.datetime #=> 2014-12-27 02:16:23 +0900
34
+
35
+ Time.now #=> 2014-12-27 02:01:23 +0900
36
+ ```
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it ( https://github.com/[my-github-username]/hijiri/fork )
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/hijiri.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hijiri/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hijiri"
8
+ spec.version = Hijiri::VERSION
9
+ spec.authors = ["kkosuge"]
10
+ spec.email = ["root@kksg.net"]
11
+ spec.summary = %q{Derive Time from Time expression with Japanese language.}
12
+ spec.description = %q{日本語の文中に含まれる時刻表現をパースします。}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport"
22
+ spec.add_dependency "hashie"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,156 @@
1
+ require 'active_support/time'
2
+ require 'active_support/core_ext/object'
3
+ require 'hashie'
4
+
5
+ module Hijiri
6
+ class Parser
7
+ attr_reader :current, :original_text, :text, :results
8
+
9
+ SUB_LIST = {
10
+ /さらいねん|再来年|明後年/ => "#{2.month.from_now.year}年",
11
+ /らいねん|来年|明年|翌年/ => "#{1.month.from_now.year}年",
12
+ /らいげつ|来月/ => "#{1.month.from_now.month}月",
13
+ /あした|あす|明日/ => "#{1.day.from_now.day}日",
14
+ /あさって|みょうごにち|明後日/ => "#{2.days.from_now.day}日",
15
+ /しあさって|明々後日/ => "#{3.days.from_now.day}日"
16
+ }
17
+ CONJ_WORDS = %w(の).join('|')
18
+ TIMER_WORDS = %w(あとに 後 経った たった 経過 けいか).join('|')
19
+
20
+ def initialize(text)
21
+ @original_text = text.clone
22
+ @text = text
23
+ @results = []
24
+ @current = Time.now
25
+ end
26
+
27
+ def normalize
28
+ %w(0 1 2 3 4 5 6 7 8 9).each_with_index do |str, num|
29
+ @text.gsub!(str, num.to_s)
30
+ end
31
+ SUB_LIST.each { |key, value| @text.gsub!(key, value) }
32
+ @text
33
+ end
34
+
35
+ def remove_conj
36
+ @text.gsub!(/#{CONJ_WORDS}/, '')
37
+ end
38
+
39
+ def pluck
40
+ words = @text
41
+ .scan(/(?:(?:[\d]+年)?(?:[\d]+月)?(?:[\d]+日)?(?:[\d]+時間?)?(?:[\d]+分)?(?:[\d]+秒)?(?:#{TIMER_WORDS})?)+/)
42
+ .delete_if(&:blank?)
43
+ .delete_if{ |word| !word.match(/\d/) }
44
+ @results = words.map{ |result| Hashie::Mash.new(word: result) }
45
+ end
46
+
47
+ def scan
48
+ @results.map{ |result| result.datetime = scan_word(result[:word]) }
49
+ end
50
+
51
+ def scan_word(word)
52
+ y = word.scan(/([\d]+)年(#{TIMER_WORDS})?/).first
53
+ m = word.scan(/([\d]+)月(#{TIMER_WORDS})?/).first
54
+ d = word.scan(/([\d]+)日(#{TIMER_WORDS})?/).first
55
+ h = word.scan(/([\d]+)時(#{TIMER_WORDS})?/).first
56
+ n = word.scan(/([\d]+)分(#{TIMER_WORDS})?/).first
57
+ s = word.scan(/([\d]+)秒(#{TIMER_WORDS})?/).first
58
+
59
+ options = {}
60
+ if word.match(/(?:#{TIMER_WORDS})((?:[\d]+月)?(?:[\d]+日)?)?/)
61
+ point_word = $1
62
+ options[:month] = $1 if point_word.match(/([\d]+)月/)
63
+ options[:day] = $1 if point_word.match(/([\d]+)日/)
64
+ end
65
+
66
+ if timer?(word)
67
+ timer_time(y.try(:first),m.try(:first),d.try(:first),h.try(:first),n.try(:first),s.try(:first),options)
68
+ else
69
+ point_time(y.try(:first),m.try(:first),d.try(:first),h.try(:first),n.try(:first),s.try(:first))
70
+ end
71
+ end
72
+
73
+ def timer_time(y,m,d,h,n,s,options={})
74
+ if options[:month]
75
+ m = 0
76
+ unless options[:day]
77
+ options[:day] = 1
78
+ end
79
+ end
80
+
81
+ d = 0 if options[:day]
82
+
83
+ pass = 0
84
+ pass += y.to_i.years.to_i
85
+ pass += m.to_i.month.to_i
86
+ pass += d.to_i.days.to_i
87
+ pass += h.to_i.hours.to_i
88
+ pass += n.to_i.minutes.to_i
89
+ pass += s.to_i.seconds.to_i
90
+ res = @current + pass
91
+
92
+ if options.present?
93
+ Time.local(
94
+ res.year,
95
+ options[:month].presence || res.month,
96
+ options[:day].presence || res.day
97
+ )
98
+ else
99
+ res
100
+ end
101
+ end
102
+
103
+ def point_time(y,m,d,h,n,s)
104
+ if m && y.nil? && conv_time(y,m,d,h,n,s) < @current
105
+ y = @current.next_year.year
106
+ end
107
+ if d && m.nil? && y.nil? && conv_time(y,m,d,h,n,s) < @current
108
+ m = @current.next_month.month
109
+ return point_time(y,m,d,h,n,s)
110
+ end
111
+ if h && d.nil? && m.nil? && y.nil? && conv_time(y,m,d,h,n,s) < @current
112
+ d = @current.day + 1
113
+ if d > @current.end_of_month.day
114
+ m = @current.next_month.month
115
+ d = 1
116
+ end
117
+ return point_time(y,m,d,h,n,s)
118
+ end
119
+ if n && h.nil? && d.nil? && m.nil? && y.nil? && conv_time(y,m,d,h,n,s) < @current
120
+ h = @current.hour + 1
121
+ h = 1 if h > 24
122
+ return point_time(y,m,d,h,n,s)
123
+ end
124
+ if s && n.nil? && h.nil? && d.nil? && m.nil? && y.nil? && conv_time(y,m,d,h,n,s) < @current
125
+ n = @current.min + 1
126
+ n = 1 if n > 60
127
+ return point_time(y,m,d,h,n,s)
128
+ end
129
+
130
+ conv_time(y,m,d,h,n,s)
131
+ end
132
+
133
+ def conv_time(y,m,d,h,n,s)
134
+ Time.local(
135
+ y.presence || @current.year,
136
+ m.presence || @current.month,
137
+ d.presence || @current.day,
138
+ h.presence || @current.hour,
139
+ n.presence || @current.min,
140
+ s.presence || @current.sec
141
+ )
142
+ end
143
+
144
+ def timer?(word)
145
+ !!word.match(/#{TIMER_WORDS}/)
146
+ end
147
+
148
+ def parse
149
+ normalize
150
+ remove_conj
151
+ pluck
152
+ scan
153
+ self
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,3 @@
1
+ module Hijiri
2
+ VERSION = "0.0.1"
3
+ end
data/lib/hijiri.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "hijiri/version"
2
+ require "hijiri/parser"
3
+
4
+ module Hijiri
5
+ class << self
6
+ def parse(text)
7
+ Parser.new(text).parse
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hijiri::Parser do
4
+ describe "日時指定" do
5
+ it '年月日時分秒をパースできる' do
6
+ text = "2020年12月25日12時10分10秒"
7
+ time = Time.parse("2020/12/25 12:10:10")
8
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
9
+ expect(result).to eq(time)
10
+ end
11
+ it '年月日時分秒の全組み合わせをパースできる' do
12
+ time = Time.parse("2020/12/25 12:10:10")
13
+ methods = [:year, :month, :day, :hour, :min, :sec]
14
+ combinations = []
15
+
16
+ methods.count.times do |i|
17
+ combinations += methods.combination(i+1).to_a
18
+ end
19
+
20
+ combinations.each do |methods|
21
+ text = ""
22
+ text << "#{time.year}年" if methods.find{ |m| m == :year }
23
+ text << "#{time.month}月" if methods.find{ |m| m == :month }
24
+ text << "#{time.day}日" if methods.find{ |m| m == :day }
25
+ text << "#{time.hour}時" if methods.find{ |m| m == :hour }
26
+ text << "#{time.min}分" if methods.find{ |m| m == :min }
27
+ text << "#{time.sec}秒" if methods.find{ |m| m == :sec }
28
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
29
+ methods.each do |method|
30
+ expect(result.send(method)).to eq(time.send(method))
31
+ end
32
+ end
33
+ end
34
+ it '文章中の日時をパースできる' do
35
+ text = "Ruby 2.2.0 は2014年12月25日にリリースされました"
36
+ time = Time.parse("2014/12/25")
37
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
38
+ [:year, :month, :day].each do |method|
39
+ expect(result.send(method)).to eq(time.send(method))
40
+ end
41
+ end
42
+ it '複数の日付をパースできる' do
43
+ text = "Ruby 2.2.0 は2014年12月25日にリリースされました。今日は2018年1月27日です。"
44
+ times = [Time.parse("2014/12/25"), Time.parse("2018/1/27")]
45
+ results = Hijiri::Parser.new(text).parse.results
46
+ results.each_with_index do |result, index|
47
+ [:year, :month, :day].each do |method|
48
+ expect(result.datetime.send(method)).to eq(times[index].send(method))
49
+ end
50
+ end
51
+ end
52
+ it '日本語の日付をパースできる' do
53
+ text = "明日の天気が気になる"
54
+ time = Time.now + 1.day
55
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
56
+ [:year, :month, :day].each do |method|
57
+ expect(result.send(method)).to eq(time.send(method))
58
+ end
59
+ end
60
+ end
61
+ describe "〜時間後" do
62
+ it '1時間後' do
63
+ text = "1時間後"
64
+ time = Time.now + 1.hour
65
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
66
+ [:year, :month, :day, :hour, :min, :sec].each do |method|
67
+ expect(result.send(method)).to eq(time.send(method))
68
+ end
69
+ end
70
+ it '1年経過した時' do
71
+ text = "1年経過した時"
72
+ time = Time.now + 1.year
73
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
74
+ expect(result.year).to eq(time.year)
75
+ end
76
+ it '全角でもパースできる' do
77
+ text = "10分後"
78
+ time = Time.now + 10.minute
79
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
80
+ [:year, :month, :day, :hour, :min].each do |method|
81
+ expect(result.send(method)).to eq(time.send(method))
82
+ end
83
+ end
84
+ it '文章中の時間をパースできる' do
85
+ text = "えーと15分経ったら教えて"
86
+ time = Time.now + 15.minute
87
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
88
+ [:year, :month, :day, :hour, :min].each do |method|
89
+ expect(result.send(method)).to eq(time.send(method))
90
+ end
91
+ end
92
+ it '文章中の時間をパースできる' do
93
+ text = "えーと15分経ったら教えて"
94
+ time = Time.now + 15.minute
95
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
96
+ [:year, :month, :day, :hour, :min].each do |method|
97
+ expect(result.send(method)).to eq(time.send(method))
98
+ end
99
+ end
100
+ it '10年後の8月' do
101
+ text = "10年後の8月になったら教えて"
102
+ time = Time.now + 10.years
103
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
104
+ expect(result.year).to eq(time.year)
105
+ expect(result.month).to eq(8)
106
+ expect(result.day).to eq(1)
107
+ end
108
+ it '10年後の20日' do
109
+ text = "10年後の20日になったら教えて"
110
+ time = Time.now + 10.years
111
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
112
+ expect(result.year).to eq(time.year)
113
+ expect(result.day).to eq(20)
114
+ end
115
+ it '10年後の8月20日' do
116
+ text = "10年後の8月20日になったら教えて"
117
+ time = Time.now + 10.years
118
+ result = Hijiri::Parser.new(text).parse.results.first.datetime
119
+ expect(result.year).to eq(time.year)
120
+ expect(result.month).to eq(8)
121
+ expect(result.day).to eq(20)
122
+ end
123
+ it '複数の時間をパースできる' do
124
+ text = "えーと15分経ったら教えて。あと1年後"
125
+ result = Hijiri::Parser.new(text).parse.results
126
+ time = Time.now + 15.minute
127
+ [:year, :month, :day, :hour, :min].each do |method|
128
+ expect(result.first.datetime.send(method)).to eq(time.send(method))
129
+ end
130
+ expect(result[1].datetime.year).to eq(time.next_year.year)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hijiri do
4
+ it 'has a version number' do
5
+ expect(Hijiri::VERSION).not_to be nil
6
+ end
7
+
8
+ it 'does something useful' do
9
+ expect(Hijiri.parse('nyan')).to be_an_instance_of(Hijiri::Parser)
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'hijiri'
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hijiri
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - kkosuge
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hashie
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: "日本語の文中に含まれる時刻表現をパースします。"
84
+ email:
85
+ - root@kksg.net
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - hijiri.gemspec
96
+ - lib/hijiri.rb
97
+ - lib/hijiri/parser.rb
98
+ - lib/hijiri/version.rb
99
+ - spec/hijiri/parser_spec.rb
100
+ - spec/hijiri_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: ''
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.2.2
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Derive Time from Time expression with Japanese language.
126
+ test_files:
127
+ - spec/hijiri/parser_spec.rb
128
+ - spec/hijiri_spec.rb
129
+ - spec/spec_helper.rb
130
+ has_rdoc: