From 4d29fd21b5a47e543c99d53a7a3c03dc287fcf39 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Wed, 7 Aug 2019 02:58:45 +0300 Subject: [PATCH] chore: Add renderer docs --- README.md | 2 + lib/faker/bot/reflectors/list.rb | 5 +- lib/faker/bot/reflectors/search.rb | 45 +++++++++--- lib/faker/bot/renderer.rb | 109 +++++++++++++++++++++++++++-- 4 files changed, 144 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d9cb3cc..13ded1a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ ![faker-bot-demo](https://user-images.githubusercontent.com/17295175/62558993-c57be080-b882-11e9-972e-7588408d45c3.gif) +:book: [Code Documentation](https://www.rubydoc.info/github/faker-ruby/faker-bot) + ## Installation ```bash diff --git a/lib/faker/bot/reflectors/list.rb b/lib/faker/bot/reflectors/list.rb index 7c6c582..afb6c04 100644 --- a/lib/faker/bot/reflectors/list.rb +++ b/lib/faker/bot/reflectors/list.rb @@ -10,7 +10,7 @@ module Reflectors # @api private # class List < Reflector - # Command output filter + # Output filter # # @return [String, nil] # @@ -42,8 +42,7 @@ def initialize(options = {}) # List `Faker::Base` subclasses # - # @return [Hash{Class => }] when #show_methods is truthy - # @return [Array] when #show_methods is falsy + # @return [Hash >] when #show_methods is truthy # # @api private # diff --git a/lib/faker/bot/reflectors/search.rb b/lib/faker/bot/reflectors/search.rb index 1a32f3e..22fb783 100644 --- a/lib/faker/bot/reflectors/search.rb +++ b/lib/faker/bot/reflectors/search.rb @@ -6,18 +6,37 @@ module Faker module Bot module Reflectors # Reflection object that searches all `Faker::Base` subclass methods + # * Currently operates at O(n); improvements welcome. :) # # @api private # class Search < Reflector + # Reflector query + # + # @return [String, nil] + # + # @api private + # attr_reader :query + # Initialize search reflector + # + # @param query [String] The search query + # + # @api public + # def initialize(query) @query = query.downcase super end + # Search through `Faker::Base` subclasses and return matching results + # + # @return [Hash >] when #show_methods is truthy + # + # @api private + # def call search_descendants_matching_query descendants_with_methods @@ -25,23 +44,33 @@ def call private + # Search through `Faker::Base` subclasses and store matching results + # + # @api private + # def search_descendants_matching_query faker_descendants.each do |descendant| methods = descendant.my_singleton_methods - if query_matches_class_name?(descendant.to_s) + + if query_matches?(descendant) store(descendant, methods) else - store(descendant, methods.select { |method| query_matches_method?(method.to_s) }) + store( + descendant, + methods.select { |method| query_matches?(method) } + ) end end end - def query_matches_method?(method_name) - method_name.match(/#{query}/) - end - - def query_matches_class_name?(class_name) - class_name.downcase.match(/#{query}/) + # Match a subject against the query string + # + # @return [Boolean] + # + # @api private + # + def query_matches?(subject) + subject.to_s.match(/#{query}/i) end end end diff --git a/lib/faker/bot/renderer.rb b/lib/faker/bot/renderer.rb index 2f9ca4b..1cdf7e6 100644 --- a/lib/faker/bot/renderer.rb +++ b/lib/faker/bot/renderer.rb @@ -7,7 +7,15 @@ module Faker module Bot + # A class responsible for printing output to an [IO] interface + # + # @api private + # class Renderer + DEPRECATION_WARNING = ' ( WILL BE DEPRECATED )' + EMPTY = '' + NOT_AVAILABLE = 'N/A' + attr_reader :crayon, :hash, :options, :output, :pager def self.call(*args) @@ -15,17 +23,29 @@ def self.call(*args) end # Initialize a Render - # @param hash [Hash] # + # @param hash [Hash >] # @param options [Hash] + # @param output [IO] + # + # @api public + # def initialize(hash, options, output) @hash = hash @options = options @output = output + @crayon = Pastel.new(enabled: output.tty?) @pager = TTY::Pager.new(command: 'less -R') end + # Print paginated output if the terminal interface supports pagination. + # Otherwise, just print the full output + # + # @return [IO] + # + # @api private + # def call if paginable? pager.page(render) @@ -34,24 +54,54 @@ def call end end + # Render the structured data tree + # + # @return [String] + # + # @api private + # def render tree.render end + # Warm up the structured data tree render object + # + # @return [TTY] + # + # @api private + # def tree @tree ||= TTY::Tree.new(build_tree) end + # Check whether the terminal interface supports pagination + # + # @return [Boolean] + # + # @api private + # def paginable? gt_screen_height? && output.tty? end + # Check whether the tree size is greater than current screen height + # + # @return [Boolean] + # + # @api private + # def gt_screen_height? tree.nodes.size > TTY::Screen.height end private + # Build the structured data tree sorted alphabetically + # + # @return [Hash{Class => }] + # + # @api private + # def build_tree results = hash.reduce({}) do |h, (const, methods)| h.merge! node(const, methods&.sort) @@ -60,37 +110,84 @@ def build_tree results.sort_by(&:to_s).to_h end + # Tree node builder with color + # + # @return [Hash{Class => }] + # + # @api private + # def node(const, methods) { crayon.green(const.to_s) => leaf(const, methods) } end + # Tree leaf builder with color + # + # @return [Array] + # + # @api private + # def leaf(const, methods) (methods || []).map { |m| crayon.cyan(*leaf_args(m, const)) } end def leaf_args(method, const) - [method.to_s].tap { |arr| verbose_output(method, const, arr) if verbose? } + [method.to_s].tap do |arr| + verbose_output(method, const, arr) if verbose? + end end + # Boolean verbose option flag + # + # @return [Boolean] + # + # @api private + # def verbose? options[:verbose] end + # Generate verbose output via sample fake data + # + # @return [Array] + # + # @api private + # def verbose_output(method, const, arr) fake, message = faker_method(method, const) - arr << crayon.dim.white("=> #{fake}") << crayon.dim.magenta.bold(message.to_s) + + arr.push(crayon.dim.white("=> #{fake}")) + .push(crayon.dim.magenta.bold(message.to_s)) end + # Send message to Faker object; receive sample fake data + # + # @return [Array] + # + # @api private + # def faker_method(method, const) - [const.public_send(method), ensure_method_is_supported(method, const)] + [ + const.public_send(method), + ensure_method_is_supported(method, const) + ] rescue ArgumentError => _e - ['N/A', ''] + [NOT_AVAILABLE, EMPTY] end + # Mark deprecated methods + # + # @return [String] + # + # @api private + # def ensure_method_is_supported(method, const) - const.respond_to?(:"_deprecated_#{method}") ? ' ( WILL BE DEPRECATED )' : '' + if const.respond_to?(:"_deprecated_#{method}") + DEPRECATION_WARNING + else + EMPTY + end end end end