lib/rspec/scaffold/generator.rb in rspec-scaffold-1.0.0 vs lib/rspec/scaffold/generator.rb in rspec-scaffold-2.0.0.beta1

- old
+ new

@@ -1,49 +1,116 @@ module RSpec module Scaffold - class Generator < DelegateClass(Ryan) + class Generator + # Generates an array of lines that can be joined into an RSpec file based. + # + # @param [Ryan,#name,#funcs,#initialization_args,#class?,#module?] parser object that is used to build the rspec file - # = Class - # generate a rspec file based on existing code - - attr_reader :file - - def initialize(file) - @file = file - super Ryan.new(file) + def initialize(parser) + @parser = parser end - def const - @const ||= name.split('::').inject(Kernel) { |k, part| k.const_get part } - end + def perform(parser=nil) + # for backwards compat with arg to perform + @parser = (parser.nil? ? @parser : parser) - def perform indent = (' ' * 2) second_indent = indent * 2 - lines = [%Q(require "#{Scaffold.helper_file}"), %Q(), %Q(describe #{const} do)] - if class? - initialization_args.each do |arg| + + # header + lines = [ + %Q(# spring rspec), + %Q(describe #{@parser.name} do) + ] + + if @parser.class? + @parser.initialization_args.each do |arg| lines << %Q(#{indent}let(:#{arg.to_s.sub(/^[&*]/, '')}) {}) end lines << %Q() - lines << %Q(#{indent}subject { described_class.new #{initialization_args.join(', ')} }) - elsif module? - lines << %Q(#{indent}subject { Class.new { include #{const} }.new }) + lines << %Q(#{indent}subject { described_class.new #{@parser.initialization_args.join(', ')} }) + elsif @parser.module? + lines << %Q(#{indent}subject { Class.new { include #{@parser.name} }.new }) end + lines << %Q() - funcs.reject(&:private?).each do |func| + + # handle Rails model scopes + if scope_definitions.any? + lines << %Q|#{indent}describe 'Scopes' do| + + scope_definitions.each do |scope_name| + lines << %Q|#{second_indent}describe '.#{scope_name}' do| + lines << %Q|#{' ' * 6}xit "should collect TODO" do| + lines << %Q|#{' ' * 6}end| + lines << %Q|#{second_indent}end| + lines << %Q|| + end + + lines << %Q|#{indent}end| + lines << %Q() + end + + # handle class and instance methods + @parser.funcs.reject(&:private?).each do |func| lines << %Q(#{indent}describe "#{func.class? ? '.' : '#'}#{func.name}" do) func.assignments.each do |assignment| lines << %Q(#{second_indent}it "#{assignment}" do) << %Q(#{second_indent}end) end lines << %Q() if func.conditions.any? and func.assignments.any? func.conditions.each do |condition| lines.concat ConditionExhibit.new(condition, second_indent).render end lines << %Q(#{indent}end) << %Q() end + lines << %Q(end) << %Q() - lines + + return lines end + + private + + def scope_definitions + return @scope_definitions ||= scope_definitions_in_sexp(@parser.sexp) + end + + def scope_definitions_in_sexp(sexp_or_symbol) + is_a_cope_definition = begin + sexp_or_symbol.respond_to?(:map) && sexp_or_symbol.to_a[2] == :scope + rescue + false + end + + definitions = if is_a_cope_definition + begin + [sexp_or_symbol.to_a[3][1]] #=> scope symbol name + rescue + [nil] + end + elsif sexp_or_symbol.class == Sexp && sexp_or_symbol.size > 1 + # try looping over and going deeper + sexp_or_symbol.map do |nested_sexp| + if nested_sexp.class == Sexp && nested_sexp.size > 1 && %i|class module iter|.include?(nested_sexp[0]) + # there's nested_sexps, go deeper + nested_sexp.map do |deep_nested_sexp| + scope_definitions_in_sexp(deep_nested_sexp) + end + else + begin + [nested_sexp.to_a[3][1]] if nested_sexp.to_a[2] == :scope #=> scope symbol name + rescue + [nil] + end + end + end + else + # sexp_or_symbol happends to be a symbol, do nothing + [nil] + end + + return definitions.flatten.compact + end + end end end