timease 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
+ SHA1:
3
+ metadata.gz: e3f6aab75ab39fd2713c261b5e9acf5d0c4e2010
4
+ data.tar.gz: 74cb4e94620b3dd984778809f3e3eeb0d536e0c8
5
+ SHA512:
6
+ metadata.gz: b560e8d154e347b0b55ec5b22827c4e9bdc683d5b80f383160b734307f1cab8c7a799f0867422e579a25ecbe1a726b63779d3bbde7283d7598eeeeda33e8e6e4
7
+ data.tar.gz: dc6df45d99fc60a06d5b5194919e2aa2fdc080b3cad5f54c130f3c6c6cac13382a755db211169a0e157a52c8169a586604117b99361800c4ccee41ec542f3386
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ data/mite_mapping.yml
11
+ /log/
12
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ruby.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # TimeEase
2
+
3
+ This gem parses an arbitrary time range input into a typical time tracking app data structure.
4
+ In other words, this bridges an interest of lazy developers and one of biz time-management needs.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'timease'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install timease
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ TimeEase::Input
26
+ TimeEase::Parser
27
+ TimeEase::Output
28
+ TimeEase::Adapter::
29
+ ```
30
+
31
+ ## Development
32
+
33
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
34
+
35
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
36
+
37
+ ## Contributing
38
+
39
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kenzan100/timease.
40
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "timease"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
File without changes
@@ -0,0 +1,21 @@
1
+ projects:
2
+ -
3
+ id: 234
4
+ slug: record_sale
5
+ names:
6
+ - RecordSale
7
+ - Record Sale
8
+ - RS
9
+ -
10
+ id: 123
11
+ slug: good_travel
12
+ names:
13
+ - Good Travel
14
+ - GoodTravel
15
+
16
+ services:
17
+ -
18
+ id: 1
19
+ slug: sprint_6
20
+ names:
21
+ - Sprint6
@@ -0,0 +1,55 @@
1
+ require "yaml"
2
+ require "json"
3
+ require "rest-client"
4
+
5
+ module TimeEase::Adapter
6
+ class Mite
7
+ def initialize(parsed_output)
8
+ @parsed = parsed_output
9
+ end
10
+
11
+ def post
12
+ request_bodies.each do |req_body|
13
+ RestClient.post "#{ENV['MITE_API_HOST']}/time_entries.json",
14
+ req_body.to_json,
15
+ { content_type: :json,
16
+ accept: :json,
17
+ "X-MiteApiKey": ENV["MITE_API_KEY"] }
18
+ end
19
+ end
20
+
21
+ def request_bodies
22
+ @parsed.map do |entry|
23
+ {
24
+ time_entry: {
25
+ date_at: entry.start_at.strftime("%Y-%m-%d"),
26
+ minutes: ((entry.end_at - entry.start_at) / 60.0).to_i,
27
+ project_id: project_id(entry),
28
+ service_id: service_id(entry),
29
+ note: "#{entry.pj_name} #{entry.task_name}".strip
30
+ }
31
+ }
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def project_id(entry)
38
+ detect_id(entry, "projects", "pj_name")
39
+ end
40
+
41
+ def service_id(entry)
42
+ detect_id(entry, "services", "task_name")
43
+ end
44
+
45
+ def detect_id(entry, key, prop)
46
+ mapping[key].detect(->{{}}) { |record|
47
+ record["names"].include? entry.send(prop)
48
+ }["id"]
49
+ end
50
+
51
+ def mapping
52
+ @mapping ||= YAML.load_file("data/mite_mapping.yml")
53
+ end
54
+ end
55
+ end
data/lib/timease.rb ADDED
@@ -0,0 +1,109 @@
1
+ require "timease/version"
2
+ require "adapters/mite"
3
+ require "chronic"
4
+ require "ostruct"
5
+
6
+ module TimeEase
7
+ Input = Struct.new(:start_time, :end_time, :date, :dones) do
8
+ def valid?
9
+ [start_time, end_time, date, dones].none?{ |a| a.nil? || a.empty? }
10
+ end
11
+ end
12
+ Output = Struct.new(:start_at, :end_at, :exact, :pj_name, :task_name)
13
+
14
+ class RevParser
15
+ attr_reader :parsed_entries
16
+
17
+ def initialize(parsed_outputs)
18
+ @parsed_entries = parsed_outputs
19
+ end
20
+
21
+ def parse
22
+ parsed_entries.group_by { |e| e.start_at.to_date }.map { |date, entries|
23
+ start_time = l_time(entries.min_by { |e| e.start_at }.start_at)
24
+ end_time = l_time(entries.max_by { |e| e.end_at }.end_at)
25
+ dones = entries.sort_by { |e| e.start_at }.map { |e|
26
+ dur = (e.end_at - e.start_at) / 3600
27
+ "#{e.pj_name} #{e.task_name}(#{dur.round(2)})"
28
+ }
29
+ Input.new(start_time, end_time, l_date(date), dones)
30
+ }
31
+ end
32
+
33
+ private
34
+
35
+ def l_time(time)
36
+ time.strftime("%H:%M")
37
+ end
38
+
39
+ def l_date(time)
40
+ time.strftime("%Y-%m-%d")
41
+ end
42
+ end
43
+
44
+ class Parser
45
+ def initialize(input)
46
+ @input = input
47
+ end
48
+
49
+ def parse
50
+ projects
51
+ end
52
+
53
+ private
54
+ attr_reader :input
55
+
56
+ def projects
57
+ hours_fixed = tmp_entries.map(&:time_in_hour).reduce(:+)
58
+ if (total_hour - hours_fixed) < 0
59
+ tmp_entries.map { |t| t.time_in_hour = total_hour / tmp_entries.size.to_f }
60
+ else
61
+ entries_unfixed_time = tmp_entries.select{ |t| t.time_in_hour <= 0 }
62
+ entries_unfixed_time.map { |t| t.time_in_hour = (total_hour - hours_fixed) / entries_unfixed_time.size.to_f }
63
+ end
64
+ add_time_range!(tmp_entries, diff: 0)
65
+ end
66
+
67
+ def add_time_range!(tmp_entries, diff:)
68
+ t, *rest = tmp_entries
69
+ return [] if t.nil?
70
+ dur = t.time_in_hour * 3600
71
+ this_start_at = start_at + diff
72
+ output = Output.new(
73
+ this_start_at,
74
+ (this_start_at + dur),
75
+ false,
76
+ t.pj,
77
+ t.task
78
+ )
79
+ [output] + add_time_range!(rest, diff: diff + dur)
80
+ end
81
+
82
+ def tmp_entries
83
+ @tmp_entries ||= entries.map { |ent|
84
+ pj_name_ab, task_name_ab, time_in_hour = ent.match(reg)[1..3]
85
+ OpenStruct.new(pj: pj_name_ab, task: task_name_ab, time_in_hour: time_in_hour.to_f)
86
+ }
87
+ end
88
+
89
+ def total_hour
90
+ (end_at- start_at) / 3600.0
91
+ end
92
+
93
+ def start_at
94
+ Chronic.parse("#{input.date} #{input.start_time}")
95
+ end
96
+
97
+ def end_at
98
+ Chronic.parse("#{input.date} #{input.end_time}")
99
+ end
100
+
101
+ def reg
102
+ /(\w+)\s*(\w*)\s*\(?([\w\.]+)?\)?/
103
+ end
104
+
105
+ def entries
106
+ input.dones.split(",").map(&:strip)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,3 @@
1
+ module TimeEase
2
+ VERSION = "0.1.0"
3
+ end
data/timease.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'timease/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "timease"
8
+ spec.version = TimeEase::VERSION
9
+ spec.authors = ["Yuta Miyama Okazaki"]
10
+ spec.email = ["s04155yo@gmail.com"]
11
+
12
+ spec.summary = %q{Parses arbitray time-range inputs into typical time-tracking app data structure.}
13
+ spec.homepage = "https://github.com/kenzan100/timease"
14
+
15
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
19
+ else
20
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
21
+ end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_runtime_dependency "chronic"
29
+ spec.add_runtime_dependency "rest-client"
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "minitest", "~> 5.0"
34
+ spec.add_development_dependency "byebug"
35
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timease
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yuta Miyama Okazaki
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chronic
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: rest-client
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.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.12'
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: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - s04155yo@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - README.md
108
+ - Rakefile
109
+ - bin/console
110
+ - bin/setup
111
+ - data/inventory.yml
112
+ - data/mite_mapping.sample.yml
113
+ - data/mite_mapping.yml
114
+ - lib/adapters/mite.rb
115
+ - lib/timease.rb
116
+ - lib/timease/version.rb
117
+ - timease.gemspec
118
+ homepage: https://github.com/kenzan100/timease
119
+ licenses: []
120
+ metadata:
121
+ allowed_push_host: https://rubygems.org
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.5.1
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Parses arbitray time-range inputs into typical time-tracking app data structure.
142
+ test_files: []