standup_md 0.3.1 → 0.3.6

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.
@@ -1,9 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StandupMD
2
4
  class Config
3
5
 
4
6
  ##
5
7
  # The configuration class for StandupMD::File
6
8
  class File
9
+
10
+ ##
11
+ # The default options.
12
+ #
13
+ # @return [Hash]
14
+ DEFAULTS = {
15
+ header_date_format: '%Y-%m-%d',
16
+ header_depth: 1,
17
+ sub_header_depth: 2,
18
+ current_header: 'Current',
19
+ previous_header: 'Previous',
20
+ impediments_header: 'Impediments',
21
+ notes_header: 'Notes',
22
+ sub_header_order: %w[previous current impediments notes],
23
+ directory: ::File.join(ENV['HOME'], '.cache', 'standup_md'),
24
+ bullet_character: '-',
25
+ name_format: '%Y_%m.md',
26
+ create: true,
27
+ }
28
+
7
29
  ##
8
30
  # Number of octothorps that should preface entry headers.
9
31
  #
@@ -116,27 +138,15 @@ module StandupMD
116
138
  ##
117
139
  # Initializes the config with default values.
118
140
  def initialize
119
- reset_values
141
+ reset
120
142
  end
121
143
 
122
144
  ##
123
145
  # Sets all config values back to their defaults.
124
146
  #
125
- # @return [Boolean] true if successful
126
- def reset_values
127
- @header_date_format = '%Y-%m-%d'
128
- @header_depth = 1
129
- @sub_header_depth = 2
130
- @current_header = 'Current'
131
- @previous_header = 'Previous'
132
- @impediments_header = 'Impediments'
133
- @notes_header = 'Notes'
134
- @sub_header_order = %w[previous current impediments notes]
135
- @directory = ::File.join(ENV['HOME'], '.cache', 'standup_md')
136
- @bullet_character = '-'
137
- @name_format = '%Y_%m.md'
138
- @create = true
139
- true
147
+ # @return [Hash]
148
+ def reset
149
+ DEFAULTS.each { |k, v| instance_variable_set("@#{k}", v) }
140
150
  end
141
151
 
142
152
  ##
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'json'
3
4
 
4
5
  module StandupMD
5
-
6
6
  ##
7
7
  # Class for handling single entries. Includes the comparable module, and
8
8
  # compares by date.
@@ -38,7 +38,7 @@ module StandupMD
38
38
  attr_accessor :previous
39
39
 
40
40
  ##
41
- # Iimpediments for this entry.
41
+ # Impediments for this entry.
42
42
  #
43
43
  # @return [Array]
44
44
  attr_accessor :impediments
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module StandupMD
3
+ require 'forwardable'
4
4
 
5
+ module StandupMD
5
6
  ##
6
7
  # Enumerable list of entries.
7
8
  class EntryList
9
+ extend Forwardable
8
10
  include Enumerable
9
11
 
10
12
  ##
@@ -29,12 +31,6 @@ module StandupMD
29
31
  @entries = entries
30
32
  end
31
33
 
32
- ##
33
- # Iterate over the list and yield each entry.
34
- def each(&block)
35
- @entries.each(&block)
36
- end
37
-
38
34
  ##
39
35
  # Appends entries to list.
40
36
  #
@@ -51,24 +47,12 @@ module StandupMD
51
47
  ##
52
48
  # Finds an entry based on date. This method assumes the list has already
53
49
  # been sorted.
54
- def find(key)
55
- to_a.bsearch { |e| e.date == key }
56
- end
57
-
58
- ##
59
- # How many entries are in the list.
60
50
  #
61
- # @return [Integer]
62
- def size
63
- @entries.size
64
- end
65
-
66
- ##
67
- # Is the list empty?
51
+ # @param [Date] date
68
52
  #
69
- # @return [Boolean] true if empty
70
- def empty?
71
- @entries.empty?
53
+ # @return [StandupMD::Entry]
54
+ def find(date)
55
+ entries.bsearch { |e| e.date == date }
72
56
  end
73
57
 
74
58
  ##
@@ -124,24 +108,6 @@ module StandupMD
124
108
  self
125
109
  end
126
110
 
127
- ##
128
- # The first entry in the list. This method assumes the list has
129
- # already been sorted.
130
- #
131
- # @return [StandupMD::Entry]
132
- def first
133
- to_a.first
134
- end
135
-
136
- ##
137
- # The last entry in the list. This method assumes the list has
138
- # already been sorted.
139
- #
140
- # @return [StandupMD::Entry]
141
- def last
142
- to_a.last
143
- end
144
-
145
111
  ##
146
112
  # The list as a hash, with the dates as keys.
147
113
  #
@@ -162,5 +128,22 @@ module StandupMD
162
128
  def to_json
163
129
  to_h.to_json
164
130
  end
131
+
132
+ # :section: Delegators
133
+
134
+ ##
135
+ # The following are forwarded to @entries, which is the underly array of
136
+ # entries.
137
+ #
138
+ # +each+:: Iterate over each entry.
139
+ #
140
+ # +empty?+:: Is the list empty?
141
+ #
142
+ # +size+:: How many items are in the list?
143
+ #
144
+ # +first+:: The first record in the list.
145
+ #
146
+ # +last+:: The last record in the list.
147
+ def_delegators :@entries, :each, :empty?, :size, :first, :last
165
148
  end
166
149
  end
@@ -5,7 +5,6 @@ require 'fileutils'
5
5
  require_relative 'file/helpers'
6
6
 
7
7
  module StandupMD
8
-
9
8
  ##
10
9
  # Class for handling reading and writing standup files.
11
10
  class File
@@ -19,15 +18,34 @@ module StandupMD
19
18
  @config ||= StandupMD.config.file
20
19
  end
21
20
 
21
+ ##
22
+ # Convenience method for calling File.find(file_name).load
23
+ #
24
+ # @param [String] file_name
25
+ #
26
+ # @return [StandupMD::File]
27
+ def self.load(file_name)
28
+ unless ::File.directory?(config.directory)
29
+ raise "Dir #{config.directory} not found." unless config.create
30
+
31
+ FileUtils.mkdir_p(config.directory)
32
+ end
33
+ new(file_name).load
34
+ end
35
+
22
36
  ##
23
37
  # Find standup file in directory by file name.
24
38
  #
25
39
  # @param [String] File_naem
26
40
  def self.find(file_name)
27
- file = Dir.entries(config.directory).bsearch { |f| f == file_name }
28
- if file.nil? && !config.create
29
- raise "File #{file_name} not found." unless config.create
41
+ unless ::File.directory?(config.directory)
42
+ raise "Dir #{config.directory} not found." unless config.create
43
+
44
+ FileUtils.mkdir_p(config.directory)
30
45
  end
46
+ file = Dir.entries(config.directory).bsearch { |f| f == file_name }
47
+ raise "File #{file_name} not found." if file.nil? && !config.create
48
+
31
49
  new(file_name)
32
50
  end
33
51
 
@@ -36,8 +54,12 @@ module StandupMD
36
54
  #
37
55
  # @param [Date] date
38
56
  def self.find_by_date(date)
39
- unless date.is_a?(Date)
40
- raise ArgumentError, "Argument must be a Date object"
57
+ raise ArgumentError, 'Must be a Date object' unless date.is_a?(Date)
58
+
59
+ unless ::File.directory?(config.directory)
60
+ raise "Dir #{config.directory} not found." unless config.create
61
+
62
+ FileUtils.mkdir_p(config.directory)
41
63
  end
42
64
  find(date.strftime(config.name_format))
43
65
  end
@@ -69,6 +91,7 @@ module StandupMD
69
91
 
70
92
  unless ::File.directory?(@config.directory)
71
93
  raise "Dir #{@config.directory} not found." unless @config.create
94
+
72
95
  FileUtils.mkdir_p(@config.directory)
73
96
  end
74
97
 
@@ -76,6 +99,7 @@ module StandupMD
76
99
 
77
100
  unless ::File.file?(@name)
78
101
  raise "File #{@name} not found." unless @config.create
102
+
79
103
  FileUtils.touch(@name)
80
104
  end
81
105
 
@@ -114,21 +138,23 @@ module StandupMD
114
138
  # @return [StandupMD::FileList]
115
139
  def load
116
140
  raise "File #{name} does not exist." unless ::File.file?(name)
141
+
117
142
  entry_list = EntryList.new
118
143
  record = {}
119
144
  section_type = ''
120
145
  ::File.foreach(name) do |line|
121
146
  line.chomp!
122
147
  next if line.strip.empty?
123
- if is_header?(line)
148
+
149
+ if header?(line)
124
150
  unless record.empty?
125
151
  entry_list << new_entry(record)
126
152
  record = {}
127
153
  end
128
- record['header'] = line.sub(%r{^\#{#{@config.header_depth}}\s*}, '')
129
- section_type = @config.notes_header
130
- record[section_type] = []
131
- elsif is_sub_header?(line)
154
+ record['header'] = line.sub(/^\#{#{@config.header_depth}}\s*/, '')
155
+ section_type = @config.notes_header
156
+ record[section_type] = []
157
+ elsif sub_header?(line)
132
158
  section_type = determine_section_type(line)
133
159
  record[section_type] = []
134
160
  else
@@ -148,10 +174,10 @@ module StandupMD
148
174
  # This method is destructive; if a file for entries in the date range
149
175
  # already exists, it will be clobbered with the entries in the range.
150
176
  #
151
- # @param [Hash] start_and_end_date
177
+ # @param [Hash] {start_date: Date, end_date: Date}
152
178
  #
153
179
  # @return [Boolean] true if successful
154
- def write(dates = {})
180
+ def write(**dates)
155
181
  sorted_entries = entries.sort
156
182
  start_date = dates.fetch(:start_date, sorted_entries.first.date)
157
183
  end_date = dates.fetch(:end_date, sorted_entries.last.date)
@@ -159,9 +185,10 @@ module StandupMD
159
185
  sorted_entries.filter(start_date, end_date).sort_reverse.each do |entry|
160
186
  f.puts header(entry.date)
161
187
  @config.sub_header_order.each do |attr|
162
- tasks = entry.send(attr)
188
+ tasks = entry.public_send(attr)
163
189
  next if !tasks || tasks.empty?
164
- f.puts sub_header(@config.send("#{attr}_header").capitalize)
190
+
191
+ f.puts sub_header(@config.public_send("#{attr}_header").capitalize)
165
192
  tasks.each { |task| f.puts @config.bullet_character + ' ' + task }
166
193
  end
167
194
  f.puts
@@ -2,40 +2,38 @@
2
2
 
3
3
  module StandupMD
4
4
  class File
5
-
6
5
  ##
7
6
  # Module responsible for reading and writing standup files.
8
7
  module Helpers # :nodoc:
9
-
10
8
  private
11
9
 
12
- def is_header?(line) # :nodoc:
10
+ def header?(line) # :nodoc:
13
11
  line.match(header_regex)
14
12
  end
15
13
 
16
- def is_sub_header?(line) # :nodoc:
14
+ def sub_header?(line) # :nodoc:
17
15
  line.match(sub_header_regex)
18
16
  end
19
17
 
20
18
  def header_regex # :nodoc:
21
- %r{^#{'#' * StandupMD.config.file.header_depth}\s+}
19
+ /^#{'#' * StandupMD.config.file.header_depth}\s+/
22
20
  end
23
21
 
24
22
  def sub_header_regex # :nodoc:
25
- %r{^#{'#' * StandupMD.config.file.sub_header_depth}\s+}
23
+ /^#{'#' * StandupMD.config.file.sub_header_depth}\s+/
26
24
  end
27
25
 
28
26
  def bullet_character_regex # :nodoc:
29
- %r{\s*#{StandupMD.config.file.bullet_character}\s*}
27
+ /\s*#{StandupMD.config.file.bullet_character}\s*/
30
28
  end
31
29
 
32
30
  def determine_section_type(line) # :nodoc:
33
- line = line.sub(%r{^\#{#{StandupMD.config.file.sub_header_depth}}\s*}, '')
34
- [
35
- StandupMD.config.file.current_header,
36
- StandupMD.config.file.previous_header,
37
- StandupMD.config.file.impediments_header,
38
- StandupMD.config.file.notes_header
31
+ line = line.sub(/^\#{#{StandupMD.config.file.sub_header_depth}}\s*/, '')
32
+ [
33
+ StandupMD.config.file.current_header,
34
+ StandupMD.config.file.previous_header,
35
+ StandupMD.config.file.impediments_header,
36
+ StandupMD.config.file.notes_header
39
37
  ].each { |header| return header if line.include?(header) }
40
38
  raise "Unrecognized header [#{line}]"
41
39
  end
@@ -54,8 +52,8 @@ module StandupMD
54
52
  '#' * StandupMD.config.file.header_depth + ' ' + date.strftime(StandupMD.config.file.header_date_format)
55
53
  end
56
54
 
57
- def sub_header(sh)
58
- '#' * StandupMD.config.file.sub_header_depth + ' ' + sh
55
+ def sub_header(subhead)
56
+ '#' * StandupMD.config.file.sub_header_depth + ' ' + subhead
59
57
  end
60
58
  end
61
59
  end
@@ -1,11 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StandupMD
4
+
4
5
  ##
5
- # The gem verision
6
- #
7
- # @example
8
- # StandupMD::VERSION
9
- # # => '0.3.0'
10
- VERSION = '0.3.1'
6
+ # Module that contains all gem version information. Follows semantic
7
+ # versioning. Read: https://semver.org/
8
+ module Version
9
+
10
+ ##
11
+ # Major version.
12
+ MAJOR = 0
13
+
14
+ ##
15
+ # Minor version.
16
+ MINOR = 3
17
+
18
+ ##
19
+ # Patch version.
20
+ PATCH = 6
21
+
22
+ ##
23
+ # Version as +MAJOR.MINOR.PATCH+
24
+ def self.to_s
25
+ "#{MAJOR}.#{MINOR}.#{PATCH}"
26
+ end
27
+ end
11
28
  end
data/standup_md.gemspec CHANGED
@@ -2,7 +2,7 @@ require_relative 'lib/standup_md/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'standup_md'
5
- spec.version = StandupMD::VERSION
5
+ spec.version = StandupMD::Version.to_s
6
6
  spec.authors = ['Evan Gray']
7
7
  spec.email = 'evanthegrayt@vivaldi.net'
8
8
  spec.license = 'MIT'
@@ -12,25 +12,21 @@ Gem::Specification.new do |spec|
12
12
  spec.description = %q{Generate and edit standups in markdown format}
13
13
  spec.homepage = 'https://evanthegrayt.github.io/standup_md/'
14
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
-
20
- spec.metadata['homepage_uri'] = spec.homepage
21
- spec.metadata['source_code_uri'] = 'https://github.com/evanthegrayt/standup_md'
22
- spec.metadata['documentation_uri'] = 'https://evanthegrayt.github.io/standup_md/doc/index.html'
23
- else
15
+ unless spec.respond_to?(:metadata)
24
16
  raise 'RubyGems 2.0 or newer is required to protect against ' \
25
17
  'public gem pushes.'
26
18
  end
27
19
 
28
- # Specify which files should be added to the gem when it is released.
29
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
- # spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
- # `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
- # end
33
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] =
23
+ 'https://github.com/evanthegrayt/standup_md'
24
+ spec.metadata['documentation_uri'] =
25
+ 'https://evanthegrayt.github.io/standup_md/doc/index.html'
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
34
30
  spec.bindir = 'bin'
35
31
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
36
32
  spec.require_paths = ['lib']