lib/chusaku.rb in chusaku-0.2.0 vs lib/chusaku.rb in chusaku-0.3.0
- old
+ new
@@ -2,108 +2,125 @@
require 'chusaku/version'
require 'chusaku/parser'
require 'chusaku/routes'
+# Handles core functionality of annotating projects.
module Chusaku
- # The main method to run Chusaku. Annotate all actions in your Rails project
- # as follows:
- #
- # # @route GET /waterlilies/:id (waterlilies)
- # def show
- # # ...
- # end
- #
- # @param {Array<String>} args - CLI flags
- # @return {Integer} 0 on success, 1 on error
- def self.call(args = [])
- routes = Chusaku::Routes.call
- controller_pattern = 'app/controllers/**/*_controller.rb'
- controller_paths = Dir.glob(Rails.root.join(controller_pattern))
- annotated_paths = []
+ class << self
+ # The main method to run Chusaku. Annotate all actions in a Rails project as
+ # follows:
+ #
+ # # @route GET /waterlilies/:id (waterlilies)
+ # def show
+ # # ...
+ # end
+ #
+ # @param {Hash} flags - CLI flags
+ # @return {Integer} - 0 on success, 1 on error
+ def call(flags = {})
+ @flags = flags
+ @routes = Chusaku::Routes.call
+ @annotated_paths = []
+ controllers_pattern = 'app/controllers/**/*_controller.rb'
- # Loop over all controller file paths.
- controller_paths.each do |path|
- controller = /controllers\/(.*)_controller\.rb/.match(path)[1]
- actions = routes[controller]
- next if actions.nil?
+ Dir.glob(Rails.root.join(controllers_pattern)).each do |path|
+ controller = %r{controllers\/(.*)_controller\.rb}.match(path)[1]
+ actions = @routes[controller]
+ next if actions.nil?
- # Parse the file and iterate over the parsed content, two entries at a
- # time.
- parsed_file = Chusaku::Parser.call(path: path, actions: actions.keys)
- parsed_file[:groups].each_cons(2) do |prev, curr|
- # Remove all @route comments in the previous group.
- if prev[:type] == :comment
- prev[:body] = prev[:body].gsub(/^\s*#\s*@route.*$\n/, '')
- end
+ annotate_file(path: path, controller: controller, actions: actions.keys)
+ end
- # Only proceed if we are currently looking at an action.
+ output_results
+ end
+
+ private
+
+ # Adds annotations to the given file.
+ #
+ # @param {String} path - Path to file
+ # @param {String} controller - Controller name
+ # @param {Array<String>} actions - List of valid actions for the controller
+ # @return {void}
+ def annotate_file(path:, controller:, actions:)
+ parsed_file = Chusaku::Parser.call(path: path, actions: actions)
+ parsed_file[:groups].each_cons(2) do |prev, curr|
+ clean_group(prev)
next unless curr[:type] == :action
- # Fetch current action in routes.
- action = curr[:action]
- data = routes[controller][action]
- next unless data.any?
+ route_data = @routes[controller][curr[:action]]
+ next unless route_data.any?
- # Add annotations.
- whitespace = /^(\s*).*$/.match(curr[:body])[1]
- data.reverse.each do |datum|
- annotation = annotate(datum)
- comment = "#{whitespace}# #{annotation}\n"
- curr[:body] = comment + curr[:body]
- end
+ annotate_group(group: curr, route_data: route_data)
end
- # Write to file.
- parsed_content = parsed_file[:groups].map { |pf| pf[:body] }
- new_content = parsed_content.join
- if parsed_file[:content] != new_content
- write(path, new_content) unless args.include?(:dry)
- annotated_paths << path
+ write_to_file(path: path, parsed_file: parsed_file)
+ end
+
+ # Given a parsed group, clean out its contents.
+ #
+ # @param {Hash} group - { type: Symbol, body: String }
+ # @return {void}
+ def clean_group(group)
+ return unless group[:type] == :comment
+
+ group[:body] = group[:body].gsub(/^\s*#\s*@route.*$\n/, '')
+ group[:body] =
+ group[:body].gsub(%r{^\s*# (GET|POST|PATCH\/PUT|DELETE) \/\S+$\n}, '')
+ end
+
+ # Add an annotation to the given group given by Chusaku::Parser that looks
+ # like:
+ #
+ # @route GET /waterlilies/:id (waterlilies)
+ #
+ # @param {Hash} group - Parsed content given by Chusaku::Parser
+ # @param {Hash} route_data - Individual route data given by Chusaku::Routes
+ # @return {void}
+ def annotate_group(group:, route_data:)
+ whitespace = /^(\s*).*$/.match(group[:body])[1]
+ route_data.reverse_each do |datum|
+ name = datum[:name]
+ annotation = "@route #{datum[:verb]} #{datum[:path]}"
+ annotation += " (#{name})" unless name.nil?
+ comment = "#{whitespace}# #{annotation}\n"
+ group[:body] = comment + group[:body]
end
end
- # Output results to user.
- if annotated_paths.any?
- puts "Annotated #{annotated_paths.join(', ')}"
- if args.include?(:error_on_annotation)
- 1
- else
- 0
+ # Write annotated content to a file if it differs from the original.
+ #
+ # @param {String} path - File path to write to
+ # @param {Hash} parsed_file - Hash mutated by `annotate_group`
+ # @return {void}
+ def write_to_file(path:, parsed_file:)
+ content = parsed_file[:groups].map { |pf| pf[:body] }.join
+ return unless parsed_file[:content] != content
+
+ unless @flags.include?(:dry)
+ File.open(path, 'r+') do |file|
+ if file.respond_to?(:test_write)
+ file.test_write(content, path)
+ else
+ file.write(content)
+ end
+ end
end
- else
- puts "Nothing to annotate"
- 0
+
+ @annotated_paths.push(path)
end
- end
- # Write given content to a file. If we're using an overridden version of File,
- # then use its method instead for testing purposes.
- #
- # @param {String} path - File path to write to
- # @param {String} content - Contents of the file
- # @return {void}
- def self.write(path, content)
- File.open(path, 'r+') do |file|
- if file.respond_to?(:test_write)
- file.test_write(content, path)
+ # Output results to user.
+ #
+ # @return {Integer} - 0 for success, 1 for error
+ def output_results
+ if @annotated_paths.any?
+ puts("Annotated #{@annotated_paths.join(', ')}")
+ @flags.include?(:error_on_annotation) ? 1 : 0
else
- file.write(content)
+ puts('Nothing to annotate')
+ 0
end
end
- end
-
- # Given a hash describing an action, generate an annotation in the form:
- #
- # @route GET /waterlilies/:id (waterlilies)
- #
- # @param {Hash} action_info - Parsed line given by Chusaku::Parser
- # @return {String} Annotation for given parsed line
- def self.annotate(action_info)
- verb = action_info[:verb]
- path = action_info[:path]
- name = action_info[:name]
- annotation = "@route #{verb} #{path}"
- annotation += " (#{name})" unless name.nil?
- annotation
end
end