diff --git a/.gitignore b/.gitignore index de5eb49..e79999b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /_yardoc/ /coverage/ /doc/ +/docs /pkg/ /spec/reports/ /tmp/ @@ -11,3 +12,5 @@ .rspec_status *.gem + +.DS_store diff --git a/.rubocop.yml b/.rubocop.yml index 4c5ed9b..f6acb7f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,6 +4,9 @@ require: AllCops: NewCops: enable +Naming/BlockForwarding: + EnforcedStyle: explicit + Style/StringLiterals: Enabled: true EnforcedStyle: double_quotes diff --git a/Gemfile b/Gemfile index 3a1d2c3..0837c85 100644 --- a/Gemfile +++ b/Gemfile @@ -11,3 +11,5 @@ gem "rake", "~> 13.0" gem "rspec", "~> 3.0" gem "rubocop", "~> 1.21" gem "rubocop-rspec", "~> 2.22.0", require: false +# Documentation tool +gem "yard" diff --git a/Gemfile.lock b/Gemfile.lock index 3f46812..55109b5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,6 +56,7 @@ GEM rubocop-factory_bot (~> 2.22) ruby-progressbar (1.11.0) unicode-display_width (2.4.2) + yard (0.9.34) PLATFORMS ruby @@ -68,6 +69,7 @@ DEPENDENCIES rubocop (~> 1.21) rubocop-rspec (~> 2.22.0) slither! + yard BUNDLED WITH 2.3.25 diff --git a/README.md b/README.md index a0421ce..a1d566e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Slither by Ryan Wood http://ryanwood.com +Documentation: https://www.rubydoc.info/gems/slither + # Description: A simple, clean DSL for describing, writing, and parsing fixed-width text files. diff --git a/lib/slither/definition.rb b/lib/slither/definition.rb index ee343df..adb0e07 100644 --- a/lib/slither/definition.rb +++ b/lib/slither/definition.rb @@ -1,48 +1,96 @@ -module Slither - class Definition - attr_reader :sections, :templates, :options - - def initialize(options = {}) - @sections = [] - @templates = {} - @options = { :align => :right, :by_bytes => true }.merge(options) - end - - def section(name, options = {}, &block) - if section_using_reserved_name?(name) || section_already_defined?(name) - raise( ArgumentError, "Reserved or duplicate section name: '#{name}'") - end - - section = Slither::Section.new(name, @options.merge(options)) - section.definition = self - - yield(section) - - sections << section - section - end - - def template(name, options = {}, &block) - section = Slither::Section.new(name, @options.merge(options)) - yield(section) - @templates[name] = section - end - - def method_missing(method, *args, &block) - section(method, *args, &block) - end - - private - - def section_using_reserved_name?(name) - Section::RESERVED_NAMES.include?(name) - end - - def section_already_defined?(name) - return false if sections.empty? - - section_names = sections.map(&:name) - section_names.include?(name) - end - end -end +# frozen_string_literal: true + +module Slither + # A Definition is the parent object that contains the information about how a fixed-width file is + # formatted. It contains a collection of sections, each of which contains a collection of fields. + class Definition + attr_reader :sections, :templates, :options + + # Initializes a new Definition object. + # + # @param options [Hash] An optional hash of configuration options. + # @option options [Symbol] :align ( :right ) The alignment for fields, can be :left, :right, or :center. + # @option options [Boolean] :by_bytes ( true ) Whether to align fields by bytes or characters. + # + def initialize(options = {}) + @sections = [] + @templates = {} + @options = { align: :right, by_bytes: true }.merge(options) + end + + # Defines a new Section within the Definition. + # + # @param name [String] The name of the section. + # @param options [Hash] An optional hash of section-specific configuration options. + # @yield [Section] A block for defining fields within the section. + # @yieldparam section [Section] The section object to be configured. + # @return [Section] The newly created section. + # + # @raise [ArgumentError] if the section name is reserved or already defined. + # + # @example Define a section for the "header" part of the fixed-width file. + # definition.section(:header, align: :left) do |section| + # # The trap tells Slither which lines should fall into this section + # section.trap { |line| line[0,4] == 'HEAD' } + # # Use the boundary template for the columns + # section.template(:boundary) + # end + # + def section(name, options = {}, &block) + if section_using_reserved_name?(name) || section_already_defined?(name) + raise ArgumentError, "Reserved or duplicate section name: '#{name}'" + end + + section = Slither::Section.new(name, @options.merge(options)) + section.definition = self + + yield(section) if block + + sections << section + section + end + + # Defines a template, which can be reused to create multiple sections with the same configuration. + # + # @param name [String] The name of the template. + # @param options [Hash] An optional hash of template-specific configuration options. + # @yield [section] A block for configuring the template. + # @yieldparam section [Section] The template object to be configured. + # + # @example Define a template for the "boundary" part of the fixed-width file. + # definition.template(:boundary) do |section| + # section.column(:record_type, 4) + # section.column(::company_id, 12) + # + def template(name, options = {}, &block) + section = Slither::Section.new(name, @options.merge(options)) + yield(section) if block + @templates[name] = section + end + + # Provides a way to define sections using method calls. For example, + # you can call `my_section` instead of `section('my_section')`. + # + # @param method [Symbol] The name of the section. + # @param args [Array] Additional arguments. + # @param block [Block] A block for defining fields within the section. + # @return [Section] The newly created section. + # + def method_missing(method, *args, &block) # rubocop:disable Style/MissingRespondToMissing + section(method, *args, &block) + end + + private + + def section_using_reserved_name?(name) + Section::RESERVED_NAMES.include?(name) + end + + def section_already_defined?(name) + return false if sections.empty? + + section_names = sections.map(&:name) + section_names.include?(name) + end + end +end diff --git a/spec/slither/definition_spec.rb b/spec/slither/definition_spec.rb index 5cd8602..3243d67 100644 --- a/spec/slither/definition_spec.rb +++ b/spec/slither/definition_spec.rb @@ -20,8 +20,9 @@ subject { described_class.new } it "defaults to :right if is not specified" do - subject.section("name") do - # Empty block + subject.section("name") do |section| + section.column(:id, 10) + section.column(:name, 20) end section = subject.sections.first