dsu 1.2.1 → 2.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -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 +70 -25
- 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
|