dsu 1.2.1 → 2.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 +4 -4
- data/CHANGELOG.md +65 -21
- data/Gemfile.lock +7 -7
- data/README.md +28 -35
- data/bin/console +23 -1
- data/bin/dsu +3 -0
- data/bin/setup +14 -3
- data/exe/dsu +23 -1
- data/exe/dsu_migrate.rb +43 -0
- data/lib/core/ruby/color_theme_colors.rb +16 -0
- data/lib/core/ruby/color_theme_mode.rb +42 -0
- data/lib/core/ruby/not_today.rb +7 -0
- data/lib/core/ruby/wrap_and_join.rb +31 -0
- data/lib/dsu/base_cli.rb +19 -23
- data/lib/dsu/cli.rb +47 -37
- data/lib/dsu/command_services/add_entry_service.rb +10 -21
- data/lib/dsu/crud/json_file.rb +139 -0
- data/lib/dsu/crud/raw_json_file.rb +51 -0
- data/lib/dsu/env.rb +21 -0
- data/lib/dsu/migration/service.rb +196 -0
- data/lib/dsu/migration/version.rb +7 -0
- data/lib/dsu/models/color_theme.rb +270 -0
- data/lib/dsu/models/configuration.rb +160 -0
- data/lib/dsu/models/entry.rb +6 -2
- data/lib/dsu/models/entry_group.rb +143 -42
- data/lib/dsu/models/migration_version.rb +48 -0
- data/lib/dsu/presenters/base_presenter.rb +32 -0
- data/lib/dsu/presenters/color_theme_presenter.rb +50 -0
- data/lib/dsu/presenters/color_theme_show_presenter.rb +49 -0
- data/lib/dsu/presenters/configuration_presenter.rb +45 -0
- data/lib/dsu/presenters/entry_group_presenter.rb +35 -0
- data/lib/dsu/presenters/entry_presenter.rb +25 -0
- data/lib/dsu/services/color_theme/hydrator_service.rb +42 -0
- data/lib/dsu/services/configuration/hydrator_service.rb +42 -0
- data/lib/dsu/services/entry/hydrator_service.rb +33 -0
- data/lib/dsu/services/entry_group/editor_service.rb +107 -0
- data/lib/dsu/services/entry_group/hydrator_service.rb +37 -0
- data/lib/dsu/services/migration_version/hydrator_service.rb +36 -0
- data/lib/dsu/services/stderr_redirector_service.rb +27 -0
- data/lib/dsu/services/temp_file/reader_service.rb +33 -0
- data/lib/dsu/services/temp_file/writer_service.rb +35 -0
- data/lib/dsu/subcommands/base_subcommand.rb +14 -0
- data/lib/dsu/subcommands/config.rb +92 -32
- data/lib/dsu/subcommands/edit.rb +3 -3
- data/lib/dsu/subcommands/list.rb +70 -93
- data/lib/dsu/subcommands/theme.rb +159 -0
- data/lib/dsu/support/ask.rb +14 -19
- data/lib/dsu/support/color_themable.rb +34 -0
- data/lib/dsu/support/command_help_colorizeable.rb +27 -0
- data/lib/dsu/support/command_hookable.rb +60 -0
- data/lib/dsu/support/command_options/dsu_times.rb +32 -21
- data/lib/dsu/support/command_options/time.rb +7 -1
- data/lib/dsu/support/command_options/time_mneumonic.rb +7 -1
- data/lib/dsu/support/descriptable.rb +6 -4
- data/lib/dsu/support/entry_group_viewable.rb +28 -4
- data/lib/dsu/support/fileable.rb +94 -0
- data/lib/dsu/support/presentable.rb +11 -0
- data/lib/dsu/support/subcommand_help_colorizeable.rb +27 -0
- data/lib/dsu/support/time_comparable.rb +19 -0
- data/lib/dsu/support/time_formatable.rb +12 -0
- data/lib/dsu/support/times_sortable.rb +48 -14
- data/lib/dsu/support/utils.rb +11 -0
- data/lib/dsu/validators/color_theme_validator.rb +74 -0
- data/lib/dsu/validators/entries_validator.rb +4 -8
- data/lib/dsu/validators/version_validator.rb +29 -0
- data/lib/dsu/version.rb +2 -1
- data/lib/dsu/views/color_theme/index.rb +62 -0
- data/lib/dsu/views/color_theme/show.rb +106 -0
- data/lib/dsu/views/configuration/show.rb +41 -0
- data/lib/dsu/views/entry_group/edit.rb +3 -5
- data/lib/dsu/views/entry_group/shared/no_entries_to_display.rb +41 -0
- data/lib/dsu/views/entry_group/show.rb +16 -15
- data/lib/dsu/views/shared/error.rb +17 -0
- data/lib/dsu/views/shared/info.rb +17 -0
- data/lib/dsu/views/shared/message.rb +85 -0
- data/lib/dsu/views/shared/model_errors.rb +31 -0
- data/lib/dsu/views/shared/success.rb +17 -0
- data/lib/dsu/views/shared/warning.rb +17 -0
- data/lib/dsu.rb +22 -1
- data/lib/seed_data/themes/cherry.json +79 -0
- data/lib/seed_data/themes/default.json +79 -0
- data/lib/seed_data/themes/lemon.json +79 -0
- data/lib/seed_data/themes/matrix.json +79 -0
- data/lib/seed_data/themes/whiteout.json +79 -0
- metadata +68 -23
- data/lib/dsu/core/ruby/not_today.rb +0 -11
- data/lib/dsu/services/ai/tense_translator_service.rb +0 -63
- data/lib/dsu/services/configuration_loader_service.rb +0 -55
- data/lib/dsu/services/entry_group_deleter_service.rb +0 -31
- data/lib/dsu/services/entry_group_editor_service.rb +0 -96
- data/lib/dsu/services/entry_group_hydrator_service.rb +0 -43
- data/lib/dsu/services/entry_group_reader_service.rb +0 -36
- data/lib/dsu/services/entry_group_writer_service.rb +0 -46
- data/lib/dsu/services/entry_hydrator_service.rb +0 -35
- data/lib/dsu/services/temp_file_reader_service.rb +0 -31
- data/lib/dsu/services/temp_file_writer_service.rb +0 -33
- data/lib/dsu/support/colorable.rb +0 -14
- data/lib/dsu/support/configurable.rb +0 -15
- data/lib/dsu/support/configuration.rb +0 -112
- data/lib/dsu/support/entry_group_fileable.rb +0 -49
- data/lib/dsu/support/entry_group_loadable.rb +0 -49
- data/lib/dsu/support/folder_locations.rb +0 -21
- data/lib/dsu/support/say.rb +0 -40
- data/lib/dsu/views/edited_entries/shared/errors.rb +0 -39
- data/lib/dsu/views/shared/messages.rb +0 -56
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'erb'
|
|
4
|
-
require 'yaml'
|
|
5
|
-
require_relative '../support/configuration'
|
|
6
|
-
|
|
7
|
-
module Dsu
|
|
8
|
-
module Services
|
|
9
|
-
# This class loads an entry group file.
|
|
10
|
-
class ConfigurationLoaderService
|
|
11
|
-
include Dsu::Support::Configuration
|
|
12
|
-
|
|
13
|
-
def initialize(default_options: nil)
|
|
14
|
-
unless default_options.nil? ||
|
|
15
|
-
default_options.is_a?(Hash) ||
|
|
16
|
-
default_options.is_a?(ActiveSupport::HashWithIndifferentAccess)
|
|
17
|
-
raise ArgumentError, 'default_options must be a Hash or ActiveSupport::HashWithIndifferentAccess'
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
@default_options = default_options || {}
|
|
21
|
-
@default_options = @default_options.with_indifferent_access if @default_options.is_a?(Hash)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def call
|
|
25
|
-
config_options.merge(default_options).with_indifferent_access
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
attr_reader :default_options
|
|
31
|
-
|
|
32
|
-
def config_options
|
|
33
|
-
return default_config unless config_file?
|
|
34
|
-
|
|
35
|
-
@config_options ||= begin
|
|
36
|
-
loaded_config = YAML.safe_load(ERB.new(File.read(config_file)).result)
|
|
37
|
-
loaded_config = update_and_write_config_file!(loaded_config) unless loaded_config.keys == default_config.keys
|
|
38
|
-
loaded_config
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def update_and_write_config_file!(loaded_config)
|
|
43
|
-
loaded_config = default_config.merge(loaded_config)
|
|
44
|
-
# TODO: Make this into a configuration writer service.
|
|
45
|
-
# TODO: Test this
|
|
46
|
-
File.write(config_file, loaded_config.to_yaml)
|
|
47
|
-
loaded_config
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def default_config
|
|
51
|
-
Support::Configuration::DEFAULT_DSU_OPTIONS
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../support/entry_group_fileable'
|
|
4
|
-
|
|
5
|
-
# This class is responsible for deleting an entry group file.
|
|
6
|
-
module Dsu
|
|
7
|
-
module Services
|
|
8
|
-
class EntryGroupDeleterService
|
|
9
|
-
include Dsu::Support::EntryGroupFileable
|
|
10
|
-
|
|
11
|
-
def initialize(time:, options: {})
|
|
12
|
-
@time = time
|
|
13
|
-
@options = options || {}
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def call
|
|
17
|
-
delete_entry_group_file!
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
attr_reader :time, :options
|
|
23
|
-
|
|
24
|
-
def delete_entry_group_file!
|
|
25
|
-
return unless entry_group_file_exists?
|
|
26
|
-
|
|
27
|
-
File.delete(entry_group_file_path)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../models/entry'
|
|
4
|
-
require_relative '../support/colorable'
|
|
5
|
-
require_relative '../support/configurable'
|
|
6
|
-
require_relative '../support/say'
|
|
7
|
-
require_relative '../support/time_formatable'
|
|
8
|
-
require_relative '../views/edited_entries/shared/errors'
|
|
9
|
-
require_relative '../views/shared/messages'
|
|
10
|
-
require_relative 'stdout_redirector_service'
|
|
11
|
-
|
|
12
|
-
module Dsu
|
|
13
|
-
module Services
|
|
14
|
-
class EntryGroupEditorService
|
|
15
|
-
include Support::Colorable
|
|
16
|
-
include Support::Configurable
|
|
17
|
-
include Support::Say
|
|
18
|
-
include Support::TimeFormatable
|
|
19
|
-
|
|
20
|
-
def initialize(entry_group:, options: {})
|
|
21
|
-
raise ArgumentError, 'entry_group is nil' if entry_group.nil?
|
|
22
|
-
raise ArgumentError, 'entry_group is the wrong object type' unless entry_group.is_a?(Models::EntryGroup)
|
|
23
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash) || options.nil?
|
|
24
|
-
|
|
25
|
-
@entry_group = entry_group
|
|
26
|
-
@options = options || {}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def call
|
|
30
|
-
edit_view = render_edit_view
|
|
31
|
-
edit edit_view
|
|
32
|
-
# NOTE: Return the original entry group object as any permanent changes
|
|
33
|
-
# will have been applied to it.
|
|
34
|
-
entry_group
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
attr_reader :entry_group, :options
|
|
40
|
-
|
|
41
|
-
# Renders the edit view to a string so we can write it to a temporary file
|
|
42
|
-
# and edit it. The edits will be used to update the entry group.
|
|
43
|
-
def render_edit_view
|
|
44
|
-
say "Editing entry group #{formatted_time(time: entry_group.time)}...", HIGHLIGHT
|
|
45
|
-
StdoutRedirectorService.call { Views::EntryGroup::Edit.new(entry_group: entry_group).render }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Writes the temporary file contents to disk and opens it in the editor
|
|
49
|
-
# for editing. It then copies the changes to the entry group and writes
|
|
50
|
-
# the changes to the entry group file.
|
|
51
|
-
def edit(edit_view)
|
|
52
|
-
entry_group_with_edits = Models::EntryGroup.new(time: entry_group.time)
|
|
53
|
-
|
|
54
|
-
Services::TempFileWriterService.new(tmp_file_content: edit_view).call do |tmp_file_path|
|
|
55
|
-
if Kernel.system("${EDITOR:-#{configuration[:editor]}} #{tmp_file_path}")
|
|
56
|
-
Services::TempFileReaderService.new(tmp_file_path: tmp_file_path).call do |editor_line|
|
|
57
|
-
next unless process_description?(editor_line)
|
|
58
|
-
|
|
59
|
-
entry_group_with_edits.entries << Models::Entry.new(description: editor_line)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
process_entry_group!(entry_group_with_edits)
|
|
63
|
-
else
|
|
64
|
-
say "Failed to open temporary file in editor '#{configuration[:editor]}'; " \
|
|
65
|
-
"the system error returned was: '#{$CHILD_STATUS}'.", ERROR
|
|
66
|
-
say 'Either set the EDITOR environment variable ' \
|
|
67
|
-
'or set the dsu editor configuration option (`$ dsu config init`).', ERROR
|
|
68
|
-
say 'Run `$ dsu help config` for more information:', ERROR
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def process_entry_group!(entry_group_with_edits)
|
|
74
|
-
if entry_group_with_edits.entries.empty?
|
|
75
|
-
entry_group.delete!
|
|
76
|
-
return
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
if entry_group_with_edits.invalid?
|
|
80
|
-
header = 'The following ERRORS were encountered; these changes were not saved:'
|
|
81
|
-
messages = entry_group_with_edits.errors.full_messages
|
|
82
|
-
Views::Shared::Messages.new(messages: messages, message_type: :error, options: { header: header }).render
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Make sure we're saving only valid, unique entries.
|
|
86
|
-
entry_group.entries = entry_group_with_edits.valid_unique_entries
|
|
87
|
-
entry_group.save!
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def process_description?(description)
|
|
91
|
-
description = Models::Entry.clean_description(description)
|
|
92
|
-
!(description.blank? || description[0] == '#')
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'entry_hydrator_service'
|
|
4
|
-
|
|
5
|
-
module Dsu
|
|
6
|
-
module Services
|
|
7
|
-
class EntryGroupHydratorService
|
|
8
|
-
def initialize(entry_group_json:, options: {})
|
|
9
|
-
raise ArgumentError, 'entry_group_json is nil' if entry_group_json.nil?
|
|
10
|
-
raise ArgumentError, 'entry_group_json is the wrong object type' unless entry_group_json.is_a?(String)
|
|
11
|
-
raise ArgumentError, 'options is nil' if options.nil?
|
|
12
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
|
13
|
-
|
|
14
|
-
@entry_group_json = entry_group_json
|
|
15
|
-
@options = options || {}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
19
|
-
entry_group_hash = to_h
|
|
20
|
-
Dsu::Models::EntryGroup.new(**entry_group_hash)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
class << self
|
|
24
|
-
# Returns a Hash with :time and :entries values hydrated
|
|
25
|
-
# (i.e. Time and Entry objects respectively).
|
|
26
|
-
def to_h(entry_group_json:, options: {})
|
|
27
|
-
JSON.parse(entry_group_json, symbolize_names: true).tap do |hash|
|
|
28
|
-
hash[:time] = Time.parse(hash[:time])
|
|
29
|
-
hash[:entries] = EntryHydratorService.hydrate(entries_array: hash[:entries], options: options)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
attr_reader :entry_group_json, :options
|
|
37
|
-
|
|
38
|
-
def to_h
|
|
39
|
-
self.class.to_h(entry_group_json: entry_group_json, options: options)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../support/entry_group_fileable'
|
|
4
|
-
|
|
5
|
-
module Dsu
|
|
6
|
-
module Services
|
|
7
|
-
class EntryGroupReaderService
|
|
8
|
-
include Dsu::Support::EntryGroupFileable
|
|
9
|
-
|
|
10
|
-
def initialize(time:, options: {})
|
|
11
|
-
@time = time
|
|
12
|
-
@options = options || {}
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def call
|
|
16
|
-
read_entry_group_file
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class << self
|
|
20
|
-
def entry_group_file_exists?(time:, options: {})
|
|
21
|
-
new(time: time, options: options).send(:entry_group_file_exists?)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
attr_reader :time, :options
|
|
28
|
-
|
|
29
|
-
def read_entry_group_file
|
|
30
|
-
return {} unless entry_group_file_exists?
|
|
31
|
-
|
|
32
|
-
File.read(entry_group_file_path)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
require 'active_support/core_ext/module/delegation'
|
|
5
|
-
require_relative '../models/entry_group'
|
|
6
|
-
require_relative '../support/entry_group_fileable'
|
|
7
|
-
|
|
8
|
-
module Dsu
|
|
9
|
-
module Services
|
|
10
|
-
class EntryGroupWriterService
|
|
11
|
-
include Dsu::Support::EntryGroupFileable
|
|
12
|
-
|
|
13
|
-
delegate :time, to: :entry_group
|
|
14
|
-
|
|
15
|
-
def initialize(entry_group:, options: {})
|
|
16
|
-
raise ArgumentError, 'entry_group is nil' if entry_group.nil?
|
|
17
|
-
raise ArgumentError, 'entry_group is the wrong object type' unless entry_group.is_a?(Dsu::Models::EntryGroup)
|
|
18
|
-
raise ArgumentError, 'options is nil' if options.nil?
|
|
19
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
|
20
|
-
|
|
21
|
-
@entry_group = entry_group
|
|
22
|
-
@options = options || {}
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def call
|
|
26
|
-
entry_group.validate!
|
|
27
|
-
create_entry_group_path_if!
|
|
28
|
-
write_entry_group_to_file!
|
|
29
|
-
entry_group
|
|
30
|
-
rescue ActiveModel::ValidationError
|
|
31
|
-
puts "Error(s) encountered: #{entry_group.errors.full_messages}"
|
|
32
|
-
raise
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
attr_reader :entry_group, :options
|
|
38
|
-
|
|
39
|
-
def write_entry_group_to_file!
|
|
40
|
-
create_entry_group_path_if!
|
|
41
|
-
File.write(entry_group_file_path, JSON.pretty_generate(entry_group.to_h))
|
|
42
|
-
puts "Wrote group entry file: #{entry_group_file_path}" if ENV['ENV_DEV']
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../models/entry'
|
|
4
|
-
|
|
5
|
-
module Dsu
|
|
6
|
-
module Services
|
|
7
|
-
class EntryHydratorService
|
|
8
|
-
def initialize(entry_hash:, options: {})
|
|
9
|
-
raise ArgumentError, 'entry_hash is nil' if entry_hash.nil?
|
|
10
|
-
raise ArgumentError, 'entry_hash is the wrong object type' unless entry_hash.is_a?(Hash)
|
|
11
|
-
raise ArgumentError, 'options is nil' if options.nil?
|
|
12
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
|
13
|
-
|
|
14
|
-
@entry_hash = entry_hash
|
|
15
|
-
@options = options || {}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
19
|
-
Dsu::Models::Entry.new(**entry_hash)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
class << self
|
|
23
|
-
def hydrate(entries_array:, options: {})
|
|
24
|
-
entries_array.map do |entry_hash|
|
|
25
|
-
new(entry_hash: entry_hash, options: options).call
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
attr_reader :entry_hash, :options
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Dsu
|
|
4
|
-
module Services
|
|
5
|
-
class TempFileReaderService
|
|
6
|
-
def initialize(tmp_file_path:, options: {})
|
|
7
|
-
raise ArgumentError, 'tmp_file_path is nil' if tmp_file_path.nil?
|
|
8
|
-
raise ArgumentError, 'tmp_file_path is the wrong object type' unless tmp_file_path.is_a?(String)
|
|
9
|
-
raise ArgumentError, 'tmp_file_path is empty' if tmp_file_path.empty?
|
|
10
|
-
raise ArgumentError, 'tmp_file_path does not exist' unless File.exist?(tmp_file_path)
|
|
11
|
-
raise ArgumentError, 'options is nil' if options.nil?
|
|
12
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
|
13
|
-
|
|
14
|
-
@tmp_file_path = tmp_file_path
|
|
15
|
-
@options = options || {}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
19
|
-
raise ArgumentError, 'no block given' unless block_given?
|
|
20
|
-
|
|
21
|
-
File.foreach(tmp_file_path) do |line|
|
|
22
|
-
yield line.strip
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
|
|
28
|
-
attr_reader :tmp_file_path, :options
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'tempfile'
|
|
4
|
-
|
|
5
|
-
module Dsu
|
|
6
|
-
module Services
|
|
7
|
-
class TempFileWriterService
|
|
8
|
-
def initialize(tmp_file_content:, options: {})
|
|
9
|
-
raise ArgumentError, 'tmp_file_content is nil' if tmp_file_content.nil?
|
|
10
|
-
raise ArgumentError, 'tmp_file_content is the wrong object type' unless tmp_file_content.is_a?(String)
|
|
11
|
-
raise ArgumentError, 'options is nil' if options.nil?
|
|
12
|
-
raise ArgumentError, 'options is the wrong object type' unless options.is_a?(Hash)
|
|
13
|
-
|
|
14
|
-
@tmp_file_content = tmp_file_content
|
|
15
|
-
@options = options || {}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
19
|
-
raise ArgumentError, 'no block given' unless block_given?
|
|
20
|
-
|
|
21
|
-
Tempfile.new('dsu').tap do |file|
|
|
22
|
-
file.write("#{tmp_file_content}\n")
|
|
23
|
-
file.close
|
|
24
|
-
yield file.path
|
|
25
|
-
end.unlink
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
attr_reader :tmp_file_content, :options
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../services/configuration_loader_service'
|
|
4
|
-
|
|
5
|
-
module Dsu
|
|
6
|
-
module Support
|
|
7
|
-
# This module provides a way to configure a class, so that it can
|
|
8
|
-
# be used in a test environment.
|
|
9
|
-
module Configurable
|
|
10
|
-
def configuration
|
|
11
|
-
@configuration ||= Services::ConfigurationLoaderService.new.call
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'colorize'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
require 'yaml'
|
|
6
|
-
require_relative 'colorable'
|
|
7
|
-
require_relative 'folder_locations'
|
|
8
|
-
require_relative 'say'
|
|
9
|
-
|
|
10
|
-
module Dsu
|
|
11
|
-
module Support
|
|
12
|
-
module Configuration
|
|
13
|
-
include Colorable
|
|
14
|
-
include FolderLocations
|
|
15
|
-
include Say
|
|
16
|
-
|
|
17
|
-
CONFIG_FILENAME = '.dsu'
|
|
18
|
-
|
|
19
|
-
# rubocop:disable Style/StringHashKeys - YAML writing/loading necessitates this
|
|
20
|
-
DEFAULT_DSU_OPTIONS = {
|
|
21
|
-
# The default editor to use when editing entry groups if the EDITOR
|
|
22
|
-
# environment variable on your system is not set. On nix systmes,
|
|
23
|
-
# the default editor is`nano`. You need to change this default on
|
|
24
|
-
# Windows systems.
|
|
25
|
-
'editor' => 'nano',
|
|
26
|
-
# The order by which entries should be displayed by default:
|
|
27
|
-
# asc or desc, ascending or descending, respectively.
|
|
28
|
-
'entries_display_order' => 'desc',
|
|
29
|
-
'entries_file_name' => '%Y-%m-%d.json',
|
|
30
|
-
'entries_folder' => "#{FolderLocations.root_folder}/dsu/entries",
|
|
31
|
-
'carry_over_entries_to_today' => false,
|
|
32
|
-
# If true, when using dsu commands that list date ranges (e.g.
|
|
33
|
-
# `dsu list dates`), the displayed list will include dates that
|
|
34
|
-
# have no dsu entries. If false, the displayed list will only
|
|
35
|
-
# include dates that have dsu entries.
|
|
36
|
-
# For all other `dsu list` commands, if true, this option will
|
|
37
|
-
# behave in the aforementioned manner. If false, the displayed
|
|
38
|
-
# list will unconditionally display the first and last dates
|
|
39
|
-
# regardless of whether or not the DSU date has entries or not;
|
|
40
|
-
# all other dates will not be displayed if the DSU date has no
|
|
41
|
-
# entries.
|
|
42
|
-
'include_all' => false
|
|
43
|
-
}.freeze
|
|
44
|
-
# rubocop:enable Style/StringHashKeys
|
|
45
|
-
|
|
46
|
-
def config_file
|
|
47
|
-
File.join(root_folder, CONFIG_FILENAME)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def config_file?
|
|
51
|
-
File.exist? config_file
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def create_config_file!
|
|
55
|
-
create_config_file config_file: config_file
|
|
56
|
-
print_config_file
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def delete_config_file!
|
|
60
|
-
delete_config_file config_file: config_file
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# TODO: Move this to a view (e.g. views/configuration/show.rb)
|
|
64
|
-
def print_config_file
|
|
65
|
-
if config_file?
|
|
66
|
-
say "Config file (#{config_file}) contents:", SUCCESS
|
|
67
|
-
hash = YAML.safe_load(File.open(config_file))
|
|
68
|
-
say hash.to_yaml.gsub("\n-", "\n\n-"), SUCCESS
|
|
69
|
-
else
|
|
70
|
-
say "Config file (#{config_file}) does not exist.", WARNING
|
|
71
|
-
say ''
|
|
72
|
-
say 'The default configuration is being used:'
|
|
73
|
-
DEFAULT_DSU_OPTIONS.each_with_index do |config_entry, index|
|
|
74
|
-
say "#{index + 1}. #{config_entry[0]}: '#{config_entry[1]}'"
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private
|
|
80
|
-
|
|
81
|
-
def create_config_file(config_file:)
|
|
82
|
-
folder = File.dirname(config_file)
|
|
83
|
-
unless Dir.exist?(folder)
|
|
84
|
-
say "Destination folder for configuration file (#{folder}) does not exist", ERROR
|
|
85
|
-
return false
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
if File.exist?(config_file)
|
|
89
|
-
say "Configuration file (#{config_file}) already exists", WARNING
|
|
90
|
-
return false
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
File.write(config_file, DEFAULT_DSU_OPTIONS.to_yaml)
|
|
94
|
-
say "Configuration file (#{config_file}) created.", SUCCESS
|
|
95
|
-
|
|
96
|
-
true
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def delete_config_file(config_file:)
|
|
100
|
-
unless File.exist?(config_file)
|
|
101
|
-
say "Configuration file (#{config_file}) does not exist", WARNING
|
|
102
|
-
return false
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
File.delete config_file
|
|
106
|
-
say "Configuration file (#{config_file}) deleted", SUCCESS
|
|
107
|
-
|
|
108
|
-
true
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../services/configuration_loader_service'
|
|
4
|
-
require_relative '../support/configurable'
|
|
5
|
-
|
|
6
|
-
module Dsu
|
|
7
|
-
module Support
|
|
8
|
-
# TODO: I hate this module; refactor it!!!
|
|
9
|
-
# This module expects the following attributes to be defined: :time, :options
|
|
10
|
-
module EntryGroupFileable
|
|
11
|
-
include Support::Configurable
|
|
12
|
-
|
|
13
|
-
def entry_group_file_exists?
|
|
14
|
-
File.exist?(entry_group_file_path)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def entry_group_file_exists_for?(time:)
|
|
18
|
-
entries_file_name = time.strftime(configuration_or_options_configuration[:entries_file_name])
|
|
19
|
-
File.join(entries_folder, entries_file_name)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
def entry_group_path_exists?
|
|
25
|
-
Dir.exist?(entries_folder)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def entry_group_file_path
|
|
29
|
-
File.join(entries_folder, entries_file_name)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def entries_folder
|
|
33
|
-
@entries_folder ||= configuration_or_options_configuration[:entries_folder]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def entries_file_name
|
|
37
|
-
@entries_file_name ||= time.strftime(configuration_or_options_configuration[:entries_file_name])
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def create_entry_group_path_if!
|
|
41
|
-
FileUtils.mkdir_p(entries_folder) unless entry_group_path_exists?
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def configuration_or_options_configuration
|
|
45
|
-
@configuration_or_options_configuration ||= options[:configuration] || configuration
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'pathname'
|
|
4
|
-
require_relative '../services/entry_group_reader_service'
|
|
5
|
-
require_relative '../models/entry'
|
|
6
|
-
require_relative '../models/entry_group'
|
|
7
|
-
|
|
8
|
-
module Dsu
|
|
9
|
-
module Support
|
|
10
|
-
module EntryGroupLoadable
|
|
11
|
-
# returns an EntryGroup object loaded from
|
|
12
|
-
# the entry group json file.
|
|
13
|
-
def load(time:)
|
|
14
|
-
entry_group_json = Services::EntryGroupReaderService.new(time: time).call
|
|
15
|
-
hash = if entry_group_json.present?
|
|
16
|
-
JSON.parse(entry_group_json, symbolize_names: true).tap do |hash|
|
|
17
|
-
hash[:time] = Time.parse(hash[:time])
|
|
18
|
-
end
|
|
19
|
-
else
|
|
20
|
-
{ time: time, entries: [] }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
Models::EntryGroup.new(**hydrate_entry_group_hash(hash: hash, time: time))
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
module_function
|
|
27
|
-
|
|
28
|
-
# Accepts an entry group hash and returns a
|
|
29
|
-
# hydrated entry group hash:
|
|
30
|
-
#
|
|
31
|
-
# {
|
|
32
|
-
# time: <Time object>,
|
|
33
|
-
# entries [
|
|
34
|
-
# <Entry object 0>,
|
|
35
|
-
# <Entry object 1>,
|
|
36
|
-
# ...
|
|
37
|
-
# ]
|
|
38
|
-
# }
|
|
39
|
-
def hydrate_entry_group_hash(hash:, time:)
|
|
40
|
-
time = hash.fetch(:time, time)
|
|
41
|
-
time = Time.parse(time) unless time.is_a? Time
|
|
42
|
-
entries = hash.fetch(:entries, [])
|
|
43
|
-
entries = entries.map { |entry_hash| Models::Entry.new(**entry_hash) }
|
|
44
|
-
|
|
45
|
-
{ time: time, entries: entries }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'active_support/core_ext/object/blank'
|
|
4
|
-
require 'colorize'
|
|
5
|
-
require 'pathname'
|
|
6
|
-
|
|
7
|
-
module Dsu
|
|
8
|
-
module Support
|
|
9
|
-
module FolderLocations
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
def root_folder
|
|
13
|
-
Dir.home
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def temp_folder
|
|
17
|
-
Dir.tmpdir
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|