worklog 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: 1584302fdc1291767a62be5b3873534bec302870088fcb1ca7d707ac149dd339
4
+ data.tar.gz: 4bd2a089e9fc389f3f9b91345ba1207138713b3aae5950c64d5f3b59af5518dc
5
+ SHA512:
6
+ metadata.gz: 37c9fc32fd5e5bf1ae4ede3c57bf449b9df7aad707165846f54e7960f59ec42c0172e2aca6b97ac923bbab5c778db31964806a05422d9921ef8b47d8a631d2c6
7
+ data.tar.gz: e49fa11b381af12402e76488c3432e8140fe41e28fcf820283abfe8780675ff0c6e3ad97543ce1b0bca3f2dcc647e3f270e89ff39b29134848ff065d723bf0a7
@@ -0,0 +1,18 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 3.0.1
14
+ - name: Run the default task
15
+ run: |
16
+ gem install bundler -v 2.2.15
17
+ bundle install
18
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /lib/sandbox/
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-07-24
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in worklog.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
11
+
12
+ gem "thor", "~>1.0.1"
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ worklog (0.1.0)
5
+ thor (~> 1.0.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ minitest (5.14.4)
11
+ rake (13.0.6)
12
+ thor (1.0.1)
13
+
14
+ PLATFORMS
15
+ x64-mingw32
16
+
17
+ DEPENDENCIES
18
+ minitest (~> 5.0)
19
+ rake (~> 13.0)
20
+ thor (~> 1.0.1)
21
+ worklog!
22
+
23
+ BUNDLED WITH
24
+ 2.2.15
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Nikolay Voynov
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Worklog
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/worklog`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'worklog'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install worklog
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ 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.
30
+
31
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/worklog.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_spec.rb"]
10
+ end
11
+
12
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "worklog"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
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
data/exe/worklog ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "worklog"
5
+
6
+ rpos = ARGV.index(">")
7
+ ARGV.pop(ARGV.length - rpos) unless rpos.nil?
8
+ ARGV << 'get' if ARGV.empty?
9
+ Worklog::CLI.start(ARGV)
data/lib/worklog.rb ADDED
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "worklog/version"
4
+ require_relative "worklog/entities"
5
+ require_relative "worklog/services"
6
+ require_relative "worklog/dsl"
7
+ require_relative "worklog/cli"
8
+ require_relative "worklog/decorator"
9
+ require_relative "worklog/printer"
10
+ require "yaml"
11
+
12
+ module Worklog
13
+ class Error < StandardError; end
14
+
15
+ # FILE_MASK = "*.timelog".freeze
16
+ LOGMASK = "*.worklog".freeze
17
+ GEMHOME = ".worklog".freeze
18
+ STORAGE = "index.yml".freeze
19
+
20
+ def params
21
+ @params ||= read_params
22
+ end
23
+
24
+ def indexd
25
+ return if Dir.glob(LOGMASK).empty?
26
+ return if params[:index].include? Dir.pwd
27
+
28
+ params[:index] << Dir.pwd
29
+ home = File.join(Dir.home, GEMHOME)
30
+ Dir.mkdir(home) unless Dir.exist?(home)
31
+ File.write(
32
+ File.join(home, STORAGE),
33
+ YAML.dump(params)
34
+ )
35
+ end
36
+
37
+ protected
38
+
39
+ def read_params
40
+ para = {}
41
+
42
+ home = File.join(Dir.home, GEMHOME)
43
+ Dir.mkdir(home) unless Dir.exist?(home)
44
+
45
+ file = File.join(home, 'index.yml')
46
+ para = YAML.load(File.read(file)) if File.exist?(file)
47
+ para[:index] ||= []
48
+ para
49
+ end
50
+
51
+ def save_params
52
+ end
53
+
54
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'thor'
4
+ require_relative 'services'
5
+ include Worklog::Services
6
+
7
+ module Worklog
8
+
9
+ class CLI < Thor
10
+ include Thor::Actions
11
+ namespace :worklog
12
+
13
+ no_commands {
14
+ def under_construction
15
+ say "this feature is under construction at the moment"
16
+ end
17
+
18
+ def get_logs
19
+ if Dir.glob(Worklog::LOGMASK).empty?
20
+ say "No *.worklog files were found in this directory"
21
+ say "Run '$ worklog new' or create it yourself"
22
+ exit
23
+ end
24
+
25
+ Worklog.indexd
26
+ GetWorklogs.()
27
+ end
28
+ }
29
+
30
+ desc "version", "Show Worklog version"
31
+ def version
32
+ puts "Worklog v#{Worklog::VERSION}"
33
+ end
34
+ map %w[--version -v] => :version
35
+
36
+ desc "new [LOGNAME]", "Create timelog file LOGNAME the working directory"
37
+ def new(logname = File.basename(Dir.pwd))
38
+ filename = CreateLog.(logname)
39
+ exit if filename.empty?
40
+ say "Worklog #{filename} created"
41
+ Worklog.indexd
42
+ end
43
+
44
+ desc "get", "Show timelog report of the working directory"
45
+ def get
46
+ get_logs.each{|sh| Printer.new(Decorator.new(sh)).tracks()}
47
+ end
48
+
49
+ desc "this [PERIOD=month]", "Show timelog for this PERIOD (month/week)"
50
+ def this(period = "month")
51
+ get_logs.each do |sh|
52
+ printer = Printer.new(Decorator.new(sh))
53
+ case period
54
+ when 'month'
55
+ printer.this_month
56
+ when 'week'
57
+ printer.this_week
58
+ else
59
+ raise ArgumentError, "Unknown period '#{period}'"
60
+ end
61
+ end
62
+ end
63
+
64
+ desc "prev [PERIOD=month]", "Show timelog for prev PERIOD (month/week)"
65
+ def prev(period = "month")
66
+ get_logs.each do |sh|
67
+ printer = Printer.new(Decorator.new(sh))
68
+ case period
69
+ when 'month'
70
+ printer.prev_month
71
+ when 'week'
72
+ printer.prev_week
73
+ else
74
+ raise ArgumentError, "Unknown period '#{period}'"
75
+ end
76
+ end
77
+ end
78
+
79
+ desc "index", "Show all known timelog directories"
80
+ def index
81
+ str = Worklog.params[:index].map{|i| "- #{i}"}.join(?n)
82
+ say "Worklogs were noticed in the following places:\n#{str}"
83
+ end
84
+
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'delegate'
4
+
5
+ module Worklog
6
+
7
+ class Decorator < SimpleDelegator
8
+ def initialize(sheet)
9
+ @sheet = sheet
10
+ super
11
+ end
12
+
13
+ Person = Struct.new(:date, :spent, :task, :reward)
14
+
15
+ def tracks(filter = ->(x,_){true})
16
+ items = super().select(&filter)
17
+ .each_with_object([]) do |(date, tary), out|
18
+ out << Person.new(date,
19
+ tary.map(&:spent).inject(:+),
20
+ tary.map(&:task).join(?\n),
21
+ tary.map(&:reward).inject(:+)
22
+ )
23
+ end.sort!{|a, b| a.date <=> b.date}
24
+
25
+ {}.tap do |out|
26
+ out[:title] = title
27
+ out[:items] = items
28
+ out[:spent] = items.map(&:spent).inject(:+)
29
+ out[:total] = items.map(&:reward).inject(:+)
30
+ end
31
+ end
32
+
33
+ # TODO: this year, previous year?
34
+
35
+ def this_month
36
+ tracks(-> (x,_) { x >= start_of_month(Date.today) })
37
+ end
38
+
39
+ def prev_month
40
+ till = start_of_month(Date.today) - 1
41
+ from = start_of_month(till)
42
+ tracks(-> (x,_) { x >= from && x <= till })
43
+ end
44
+
45
+ # FIXME: incorrect for sunday 1
46
+ def this_week
47
+ today = Date.today
48
+ from = today - today.wday + 1
49
+ tracks(-> (x,_) { x >= from })
50
+ end
51
+
52
+ # FIXME: incorrect for sunday 1
53
+ def prev_week
54
+ today = Date.today
55
+ till = today - today.wday # last sunday
56
+ from = till - 6 # prev monday
57
+ tracks(-> (x,_) { x >= from && x <= till })
58
+ end
59
+
60
+ protected
61
+
62
+ def start_of_month(date)
63
+ Date.new(date.year, date.month, 1)
64
+ end
65
+
66
+ def end_of_month(date)
67
+ Date.new(date.year, date.month, -1)
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'entities'
4
+ include Worklog::Entities
5
+
6
+ module Worklog
7
+
8
+ # This class provides DSL for timelogging
9
+ #
10
+ # @example
11
+ # sheet = DSL.build() do
12
+ # title "Worklog"
13
+ # date_format "%Y-%m-%d"
14
+ # hourly_rate 20
15
+ #
16
+ # track '2021-07-10', spent: '8h', task: 'work on func requirements'
17
+ # track '2021-07-11', spent: '8h', task: 'work on func requirements'
18
+ # track '2021-07-12', spent: '8h30m', task: 'work on use cases'
19
+ # track '2021-07-13', spent: '30m', task: 'work on user stories'
20
+ # track '2021-07-13', spent: '7h30m', task: 'administrator user stories'
21
+ # end
22
+ #
23
+ # @example
24
+ # sheet = DSL.build() { read File.read('project.timesheet') }
25
+ class DSL
26
+ attr_reader :sheet
27
+
28
+ def self.build(&block)
29
+ dsl = new
30
+ dsl.instance_eval(&block) if block_given?
31
+ dsl.sheet
32
+ end
33
+
34
+ private_class_method :new
35
+
36
+ def initialize
37
+ @sheet = Sheet.new
38
+ end
39
+
40
+ def title(title)
41
+ @sheet.title = title
42
+ end
43
+
44
+ def date_format(fmt)
45
+ @sheet.date_format = fmt
46
+ end
47
+
48
+ def hourly_rate(rate)
49
+ @sheet.hourly_rate = rate
50
+ end
51
+
52
+ def read(text)
53
+ instance_eval text
54
+ end
55
+
56
+ def read_file(filename)
57
+ text = File.read(filename)
58
+ read text
59
+ @sheet.source = filename
60
+ end
61
+
62
+ def track(date, spent:, task: '', rate: nil)
63
+ @sheet.track(
64
+ Date.strptime(date, @sheet.date_format),
65
+ spent: parse_spent(spent),
66
+ rate: rate,
67
+ task: task
68
+ )
69
+ end
70
+
71
+ def parse_spent(time)
72
+ regx = /^((\d{1,2})[hH])?\s?((\d{1,2})[mM])?$/
73
+ data = time.match(regx)
74
+ raise ArgumentError, "\"spent\" format \"\d{1,2}[Hh]d{1,2}[Mm]\"" unless data
75
+ h = data[2] || 0
76
+ m = data[4] || 0
77
+ h.to_i * 60 + m.to_i
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "entities/track"
2
+ require_relative "entities/sheet"
3
+
4
+ module Worklog
5
+ module Entities
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'bigdecimal'
4
+ require 'date'
5
+ require_relative 'track'
6
+
7
+ module Worklog
8
+ module Entities
9
+
10
+ # This class represent sheet of tracks collection
11
+ class Sheet
12
+ attr_reader :tracks
13
+ attr_accessor :source
14
+ attr_accessor :date_format
15
+ attr_accessor :hourly_rate
16
+ attr_accessor :title
17
+
18
+
19
+ def initialize
20
+ @tracks = {}
21
+ @date_format = "%Y-%m-%d"
22
+ @hourly_rate = 0
23
+ @title = ""
24
+ end
25
+
26
+ # This method adds new track to the sheet
27
+ # It will pring warning, when total spent for one date exceeds 24h
28
+ # @param date [Date] the track date
29
+ # @param spent [Number] the track spent time in minutes
30
+ # @param task [String] the tracking task description
31
+ # @param rate [Number] the track hourly rate, optional; provide it when the track hourly rate differs from specified for whole sheet (weekends, overtime, or sth)
32
+ # @return [Track] the track registered
33
+ def track(date, spent:, task:, rate: nil)
34
+ @tracks[date] ||= []
35
+ @tracks[date] << Track.new(
36
+ date,
37
+ spent: spent,
38
+ task: task,
39
+ rate: rate || @hourly_rate
40
+ )
41
+ if @tracks[date].size > 1 && spent_for(date) > Track::MAX_MINUTES
42
+ puts "Warning! Total spent for #{date} greater than 24 hours"
43
+ end
44
+ @tracks[date].last
45
+ end
46
+
47
+ # The method calculates sum(spent) for provided date
48
+ # @param date [Date] the date for calculation
49
+ # @retun [Number] sum of spent for the date
50
+ def spent_for(date)
51
+ @tracks[date].map(&:spent).inject(:+)
52
+ end
53
+
54
+ # The method merges tracks from sheet passed as param
55
+ def merge!(sheet)
56
+ @tracks.merge!(sheet.tracks) do |date, these_tracks, merge_tracks|
57
+ puts "Warning! Date duplication detected in '#{@source}' and '#{sheet.source}'"
58
+ puts "Please, check these files manually for '#{date.to_s}'"
59
+ these_tracks + merge_tracks
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'bigdecimal'
4
+ require 'date'
5
+
6
+ module Worklog
7
+ module Entities
8
+
9
+ # This class represent the abstraction of a timelog item
10
+ class Track
11
+ attr_reader :date
12
+ attr_reader :rate
13
+ attr_reader :task
14
+ attr_reader :spent
15
+ attr_reader :reward
16
+
17
+ # @param date [Time] the date of the track
18
+ # @param rate [Float] the rate of the track
19
+ # @param spent [Integer] minutes spent of the track
20
+ # @param task [String] the task descritpion of the track
21
+ def initialize(date, spent:, rate: 0, task: "")
22
+ # the spent cannot be more than a day of 24 hours
23
+ raise ArgumentError, ":spent exceeds 24 hours" if spent > MAX_MINUTES
24
+ # the date cannot be in the future
25
+ date = date.to_date unless date.is_a? Date
26
+ raise ArgumentError, ":date in the future" if date > Date.today
27
+ @date = date
28
+ @rate = rate
29
+ @task = task
30
+ @spent = spent
31
+ reward = BigDecimal(spent.to_s) / BigDecimal(60) * BigDecimal(rate.to_s)
32
+ @reward = reward.round(2, :half_down)
33
+ end
34
+
35
+ MAX_MINUTES = 1440
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'delegate'
4
+
5
+ module Worklog
6
+
7
+ class Printer < SimpleDelegator
8
+ def initialize(sheet)
9
+ @sheet = sheet
10
+ super
11
+ end
12
+
13
+ # TODO: header for this/prev month/week
14
+ # TODO: grouping by months if there are more than one
15
+ def print(report, subtitle = "")
16
+ puts "-= #{report[:title]} #{subtitle} =-"
17
+ puts %w(Date Year Month Week Spent Reward Task).join(?\t)
18
+ report[:items].each do |track|
19
+ row = [].tap do |r|
20
+ r << track.date.to_s
21
+ r << track.date.year
22
+ r << track.date.strftime('%B')
23
+ r << track.date.cweek
24
+ r << format_spent(track.spent)
25
+ r << track.reward.to_s(?F)
26
+ r << track.task
27
+ end.join(?\t)
28
+ puts row
29
+ end
30
+ puts
31
+ puts "Total time\t#{format_spent(report[:spent])}"
32
+ puts "Total\t%.2f" % report[:total]
33
+ end
34
+
35
+ def tracks(filter = ->(x,_){true})
36
+ print(super(&filter))
37
+ end
38
+
39
+ def this_month
40
+ subtitle = "for #{Date.today.strftime("%B %Y")}"
41
+ print(super(), subtitle);
42
+ end
43
+
44
+ def prev_month
45
+ subtitle = "for #{(Date.today << 1).strftime("%B %Y")}"
46
+ print(super(), subtitle)
47
+ end
48
+
49
+ def this_week; print(super()); end
50
+ def prev_week; print(super()); end
51
+
52
+ protected
53
+
54
+ def format_spent(spent)
55
+ h = spent / 60
56
+ m = spent % 60
57
+ [].tap do |out|
58
+ out << "#{h}h" if h > 0
59
+ out << "#{m}m" if m > 0
60
+ end.join(" ")
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,8 @@
1
+ require_relative "services/service"
2
+ require_relative "services/get_timelogs"
3
+ require_relative "services/new_timelog"
4
+
5
+ module Worklog
6
+ module Services
7
+ end
8
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'service'
4
+ require_relative '../dsl'
5
+
6
+ module Worklog
7
+ module Services
8
+ include Worklog
9
+
10
+ # This service loads all timelogs in the working directory. Several
11
+ # timelogs that share the same title will be merged to single sheet
12
+ # with the shared title
13
+ # @example
14
+ # GetLogsWorkDir.() # => Array<Sheet>
15
+ class GetWorklogs < Service
16
+
17
+ def call
18
+ [].tap do |logs|
19
+ Dir.glob(::LOGMASK) do |f|
20
+ puts "Processing #{f}.."
21
+ flog = DSL.build() { read_file(f) }
22
+ # merge by sheet title
23
+ mlog = logs.find{|i| i.title == flog.title}
24
+ mlog.nil? ? logs << flog : mlog.merge!(flog)
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'service'
4
+ require 'date'
5
+
6
+ module Worklog
7
+ module Services
8
+ include Worklog
9
+
10
+ # This service creates timelog file in the working directory.
11
+ # and returns name of the created file '<folder_name>.timelog'
12
+ # If file with this name exits
13
+ # @example
14
+ class NewWorklog < Service
15
+ def call
16
+ filename = @logname + Worklog::LOGMASK[1..-1]
17
+ if File.exist? filename
18
+ puts "Operation canceled. File with name '#{filename}' already exists"
19
+ return ''
20
+ end
21
+ File.write(filename, LOGCONTENT % [@logname, Date.today.to_s])
22
+ filename
23
+ end
24
+
25
+ def initialize(logname)
26
+ @logname = logname
27
+ end
28
+
29
+ LOGCONTENT = <<~EOF
30
+ title %s
31
+ hourly_rate 20
32
+ date_format '%%Y-%%m-%%d'
33
+
34
+ track '%s', spent: '1h', task: 'created timelog ..'
35
+ EOF
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ module Worklog
4
+ module Services
5
+
6
+ class Service
7
+ if RUBY_VERSION =~ /3\.[[:digit:]]+\.[[:digit:]]/
8
+ def self.call(*args, **opts)
9
+ new(*args, **opts).call
10
+ end
11
+ else
12
+ def self.call(*args)
13
+ new(*args).call
14
+ end
15
+ end
16
+
17
+ private_class_method :new
18
+
19
+ # Should be implemented in subclasses
20
+ def call
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Worklog
4
+ VERSION = "0.1.0"
5
+ end
data/worklog.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/worklog/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "worklog"
7
+ spec.version = Worklog::VERSION
8
+ spec.authors = ["Nikolay Voynov"]
9
+ spec.email = ["nvoynov@gmail.com"]
10
+
11
+ spec.summary = "Time logging DSL and CLI for extended reporting"
12
+ spec.description = %q(The Worklog gem provides a simple domain-specific language (DSL) for tracking work time and a command-line interface (CLI) for processing the time spent. It'll answer some basic questions like "how much time I've spent on this project this month?" or "how much I've earned the previous week?")
13
+ spec.homepage = "https://github.com/nvoynov/worklog"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/nvoynov/worklog"
21
+ spec.metadata["changelog_uri"] = "https://github.com/nvoynov/worklog/CHANGELOG.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ # Uncomment to register a new dependency of your gem
33
+ # spec.add_dependency "example-gem", "~> 1.0"
34
+ spec.add_dependency "thor", "~> 1.0.1"
35
+
36
+ # For more information and examples about making a new gem, checkout our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: worklog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nikolay Voynov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.1
27
+ description: The Worklog gem provides a simple domain-specific language (DSL) for
28
+ tracking work time and a command-line interface (CLI) for processing the time spent.
29
+ It'll answer some basic questions like "how much time I've spent on this project
30
+ this month?" or "how much I've earned the previous week?"
31
+ email:
32
+ - nvoynov@gmail.com
33
+ executables:
34
+ - worklog
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ".github/workflows/main.yml"
39
+ - ".gitignore"
40
+ - CHANGELOG.md
41
+ - Gemfile
42
+ - Gemfile.lock
43
+ - LICENSE.txt
44
+ - README.md
45
+ - Rakefile
46
+ - bin/console
47
+ - bin/setup
48
+ - exe/worklog
49
+ - lib/worklog.rb
50
+ - lib/worklog/cli.rb
51
+ - lib/worklog/decorator.rb
52
+ - lib/worklog/dsl.rb
53
+ - lib/worklog/entities.rb
54
+ - lib/worklog/entities/sheet.rb
55
+ - lib/worklog/entities/track.rb
56
+ - lib/worklog/printer.rb
57
+ - lib/worklog/services.rb
58
+ - lib/worklog/services/get_timelogs.rb
59
+ - lib/worklog/services/new_timelog.rb
60
+ - lib/worklog/services/service.rb
61
+ - lib/worklog/version.rb
62
+ - worklog.gemspec
63
+ homepage: https://github.com/nvoynov/worklog
64
+ licenses:
65
+ - MIT
66
+ metadata:
67
+ allowed_push_host: https://rubygems.org
68
+ homepage_uri: https://github.com/nvoynov/worklog
69
+ source_code_uri: https://github.com/nvoynov/worklog
70
+ changelog_uri: https://github.com/nvoynov/worklog/CHANGELOG.md
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 2.4.0
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 3.2.15
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Time logging DSL and CLI for extended reporting
90
+ test_files: []