Skip to content

Commit

Permalink
Add yard to Rakefile + YARD doc improvements/fixes
Browse files Browse the repository at this point in the history
Running `rake` will now run Yard as well. This provides relevant output
to indicate when the YARD documentation isn't compiling properly or when
code is undocumented.

Improve uniformity of YARD documentation and fix some formatting issues.

Remove some reek directives that have leaded through into the
documentation by spacing it apart from the existing documentation.

Add some missing documentation.
  • Loading branch information
Paul DobbinSchmaltz committed Nov 13, 2023
1 parent f39b71b commit 9a9a736
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 79 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ The regular expressions and HEX codes used in the screenshot are:

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. Or, run `rake` to run the tests plus linters. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. Or, run `rake` to run the tests plus linters as well as `yard` (to confirm proper YARD documentation practices). You can also run `bin/console` for an interactive prompt that will allow you to experiment.

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`, bump the latest ruby target versions etc. with `rake bump`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and attempt to push the `.gem` file to [rubygems.org](https://rubygems.org) -- NOTE: this gem doesn't live on rubygems.org because of a naming conflict, so the upload attempt can be aborted when 2FA is requested.

Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ task :default do
test
rubocop
reek
yard
])
end

Expand Down
10 changes: 10 additions & 0 deletions lib/say/generators/banner_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

# Say::Banner is a generator for (justified) banner Strings.
module Say::BannerGenerator
# Generate a justified banner String.
#
# @param text [String] The text to be included in the banner.
# If `text` is empty, the banner will be of type `:hr`.
# Else the banner will be of type `:title`.
# @param columns [Integer] The desired overall String length; may not be
# respected if the `text` + minimal banner elements are greater than
# `columns` in length.
# @param justify [#to_s] One of %i[left center right]; Text justification vs
# overall banner length.
def self.call(text, columns:, justify:)
interpolation_template = build_interpolation_template(text)
interpolation_template.public_send(
Expand Down
77 changes: 48 additions & 29 deletions lib/say/interpolation_template.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# frozen_string_literal: true

# :reek:TooManyInstanceVariables
# :reek:DataClump

# Say::InterpolationTemplate is a value object that represents an
# interpolation template for interpolating text and creating banners of a
# specified length.
#
# Each segment of the interpolation template affects the output string as
# specified:
# - {#left_bookend} always anchored to left side of the output string; does
# not factor into string length for justification purposes.
# not factor into string length for justification purposes.
# - {#left_fill} the repeatable portion of the string to the left of the spacer
# and the given text.
# and the given text.
# - {#left_spacer} a static string inserted to the left of the given text.
# - `text` is the given text that is to be interpolated into the template.
# - {#right_spacer} a static string inserted to the right of the given text.
# - {#right_fill} the repeatable portion of the string to the right of the
# spacer and the given text.
# spacer and the given text.
# - {#right_bookend} always anchored to right side of the output string; does
# not factor into string length for justification purposes.
# not factor into string length for justification purposes.
#
# @example Default Template
# interpolation_template = Say::InterpolationTemplate.new
Expand All @@ -33,14 +36,9 @@
# right_bookend: "RBE")
# interpolation_template.interpolate("TEST") # => "LBE< TEST >RBE"
#
# @see Say::InterpolationTemplate::Builder For built-in/pre-defined
# templates.
#
# :reek:TooManyInstanceVariables
# :reek:DataClump
# @see Say::InterpolationTemplate::Builder Say::InterpolationTemplate::Builder
# -- for built-in/pre-defined templates.
class Say::InterpolationTemplate
DEFAULT_LENGTH = Say::MAX_COLUMNS

# A symbolic representation of the portion of the interpolation template
# string that should be replaced with the given `text` during interpolation.
INTERPOLATION_SENTINEL = "{}"
Expand All @@ -52,12 +50,10 @@ class Say::InterpolationTemplate
:right_fill,
:right_bookend

# @return [Say::InterpolationTemplate] The newly created interpolation
# template object.
#
# rubocop:disable Metrics/ParameterLists
# :reek:LongParameterList
# :reek:TooManyStatements

def initialize(
left_bookend: nil,
left_fill: nil,
Expand Down Expand Up @@ -120,19 +116,37 @@ def interpolate(text = "")
].join
end

def left_justify(text = "", length: DEFAULT_LENGTH)
# Output a left-justified banner of the given `length`.
#
# @param text [String]
# @param length [Integer]
#
# @return [String]
def left_justify(text = "", length: Say::MAX_COLUMNS)
justifier =
Say::LeftJustifier.new(interpolation_template: self, length: length)
justifier.call(text)
end

def center_justify(text = "", length: DEFAULT_LENGTH)
# Output a center-justified banner of the given `length`.
#
# @param text [String]
# @param length [Integer]
#
# @return [String]
def center_justify(text = "", length: Say::MAX_COLUMNS)
justifier =
Say::CenterJustifier.new(interpolation_template: self, length: length)
justifier.call(text)
end

def right_justify(text = "", length: DEFAULT_LENGTH)
# Output a right-justified banner of the given `length`.
#
# @param text [String]
# @param length [Integer]
#
# @return [String]
def right_justify(text = "", length: Say::MAX_COLUMNS)
justifier =
Say::RightJustifier.new(interpolation_template: self, length: length)
justifier.call(text)
Expand Down Expand Up @@ -171,23 +185,25 @@ def right_fill?
#
# The default Interpolation Template class is {Say::InterpolationTemplate}.
module Builder
DEFAULT_INTERPOLATION_TEMPLATE_CLASS = Say::InterpolationTemplate
# The default Predefined Interpolation Template to use, if no other name is
# provided.
DEFAULT_INTERPOLATION_TEMPLATE_NAME = :title

DEFAULT_TYPE = :title
TYPES = {
# Predefined Interpolation Templates by name and attributes hash.
DEFAULT_INTERPOLATION_TEMPLATES = {
DEFAULT_INTERPOLATION_TEMPLATE_NAME => {
left_fill: "=", left_spacer: " ", right_spacer: " ", right_fill: "="
},
hr: {
left_fill: "=", right_fill: "="
},
DEFAULT_TYPE => {
left_fill: "=", left_spacer: " ", right_spacer: " ", right_fill: "="
},
wtf: {
left_fill: "?", left_spacer: " ", right_spacer: " ", right_fill: "?"
},
}.freeze

# rubocop:disable Style/CommentedKeyword
TYPES.each_key do |type_name|
DEFAULT_INTERPOLATION_TEMPLATES.each_key do |type_name|
define_singleton_method(type_name) do # def self.<type_name>
call(type_name) # call(<type_name))
end # end
Expand All @@ -200,33 +216,36 @@ module Builder
# through untouched.
def self.call(
type_or_template = nil,
interpolation_template_class: DEFAULT_INTERPOLATION_TEMPLATE_CLASS)
interpolation_template_class: Say::InterpolationTemplate)
if type_or_template.is_a?(interpolation_template_class)
return type_or_template
end

interpolation_template_attributes =
to_interpolation_template_attributes(type_or_template || DEFAULT_TYPE)
to_interpolation_template_attributes(
type_or_template || DEFAULT_INTERPOLATION_TEMPLATE_NAME)
interpolation_template_class.new(**interpolation_template_attributes)
end

# @param type_or_template [#to_sym] one of `TYPES.keys`.
# @param type_name_or_template_attributes [#to_sym] One of
# `DEFAULT_INTERPOLATION_TEMPLATES.keys`.
def self.to_interpolation_template_attributes(
type_name_or_template_attributes)
case type_name_or_template_attributes
when Hash
type_name_or_template_attributes
else
TYPES.fetch(type_name_or_template_attributes.to_sym)
DEFAULT_INTERPOLATION_TEMPLATES.fetch(
type_name_or_template_attributes.to_sym)
end
end
end

# rubocop:disable all
# :nocov:
# @!visibility private

# Usage: Say::InterpolationTemplate.test;
# @!visibility private
def self.test
Say.("Say::InterpolationTemplate.test") do
interpolation_template_attributes_set = [
Expand Down
15 changes: 9 additions & 6 deletions lib/say/justifiers/justifier_behaviors.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
# frozen_string_literal: true

# :reek:ModuleInitialize

# Say::JustifierBehaviors is a mix-in that defines common
# left/center/right-justification behaviors.
#
# @see Say::LeftJustifier
# @see Say::CenterJustifier
# @see Say::RightJustifier
#
# :reek:ModuleInitialize
module Say::JustifierBehaviors
# The default fill pattern to use if {#left_fill} or {#right_fill} is not
# provided. It's important to use a space in this case, so that
# left/center/right-justification can still work--as an empty string cannot
# effectively shift a string over one way or another.
DEFAULT_FILL_PATTERN = " "
DEFAULT_LENGTH = Say::MAX_COLUMNS

attr_reader :interpolation_template,
:total_length

# @param interpolation_template [Say::InterpolationTemplate]
# @param length [Integer] how long the output String should aim to be, at
# @param length [Integer] How long the output String should aim to be, at
# most. Will not truncate.
def initialize(interpolation_template:, length: DEFAULT_LENGTH)
def initialize(interpolation_template:, length: Say::MAX_COLUMNS)
@interpolation_template = interpolation_template
@total_length = Integer(length)
end

# Justify the given {#text} and wrap with left/right bookends. If a block is
# Justify the given `text` and wrap with left/right bookends. If a block is
# given, then this will override anything passed by the `text` attribute.
#
# @return [String]
Expand Down
20 changes: 12 additions & 8 deletions lib/say/message.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Say::Message represents the user-supplied text and type, to be output by the
# various Say.* methods.
# Say::Message represents the user-supplied text and output type, to be
# outputted by the various Say.* methods.
#
# @example Default Output, given no text or type
# Say::Message.new.to_s # => " ..."
Expand All @@ -18,6 +18,7 @@
# Say::Message.new("Test", type: :warn).to_s # => " !¡ Test"
# Say::Message.new.to_s # => " ..."
class Say::Message
# The default Message "TYPE" if no `type` name is provided.
DEFAULT_TYPE = :success

# Mapping of message types to their corresponding prefixes for the `say`
Expand All @@ -35,25 +36,28 @@ class Say::Message
debug: " >> ",
error: " ** ",
info: " -- ",
success: hash.default,
DEFAULT_TYPE => hash.default,
warn: " !¡ ")
}.freeze

# The default message to use when one is not supplied.
DEFAULT_MESSAGE = " ..."

attr_reader :type,
:text
attr_reader :text,
:type

# @param text [String] (DEFAULT_MESSAGE) The user-supplied text.
# @param type [Symbol] (optional) One of Say::Message::TYPES.keys
# :reek:ControlParameter

# @param text [String] (DEFAULT_MESSAGE) The user-supplied text.
# @param type [Symbol] One of Say::Message::TYPES.keys
def initialize(text = nil, type: DEFAULT_TYPE)
@text = text
@type = type || DEFAULT_TYPE
end

# @return [String] Returns the built message String.
# Return the built message as a String.
#
# @return [String]
def to_s
return DEFAULT_MESSAGE unless text

Expand Down
12 changes: 6 additions & 6 deletions lib/say/progress/interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ def initialize(tracker: Say::Progress::Tracker.new)
# no block is given) if this is an on-interval tick. If a block is given it
# will always be called, regardless.
#
# @param text [String] (optional) The message to be printed.
# @param type [Symbol] (optional) The type of the message.
# @param text [String] The message to be printed.
# @param type [Symbol] The type of the message.
# (see Say::Message::TYPES)
# Note: `type` is ignored if a block is given.
# @param block [Proc] (optional) A block of code to be called with header and
# footer banners.
# @param block [Proc] A block of code to be called with header and footer
# banners.
#
# @return [] Returns the result of the called block if a block is given.
def say(text = nil, type = nil, index: self.index, &block)
Expand All @@ -52,7 +52,7 @@ def say(text = nil, type = nil, index: self.index, &block)
# Must be called manually by the client code because automatic index updating
# is less reliable.
#
# @param index [Integer, nil] the current index number we're on for this
# @param index [Integer, nil] The current index number we're on for this
# Interval.
#
# @return [self]
Expand All @@ -78,9 +78,9 @@ def index

# rubocop:disable all
# :nocov:
# @!visibility private

# Usage: Say::Progress::Interval.test;
# @!visibility private
def self.test
require "timecop"
Timecop.freeze(Say::Time.test_sample)
Expand Down
7 changes: 5 additions & 2 deletions lib/say/progress/tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
#
# @see Say::Progress::Interval
class Say::Progress::Tracker
# The default "interval" to use for ticks in a loop if no `interval` is
# provided. i.e. the default is to provide continuous ticking/updating for
# every loop iteration.
DEFAULT_INTERVAL = 1

attr_reader :interval,
:index

# @param interval [Integer] Indexes at which the current tick in a loop will
# be considered on-interval.
# @param index [Integer] the current iteration through a loop.
# @param index [Integer] The current iteration through a loop.
def initialize(interval: DEFAULT_INTERVAL, index: 0)
@interval = Integer(interval)
@index = Integer(index)
Expand Down Expand Up @@ -54,9 +57,9 @@ def tick?

# rubocop:disable all
# :nocov:
# @!visibility private

# Usage: Say::Progress::Tracker.test;
# @!visibility private
def self.test
Say.("Say::Progress::Tracker.test") do
i1 = Say::Progress::Tracker.new
Expand Down
Loading

0 comments on commit 9a9a736

Please sign in to comment.