Repository: Nedomas/zapata Branch: master Commit: 548ea9334e24 Files: 131 Total size: 91.8 KB Directory structure: gitextract_g8mieinx/ ├── .gitignore ├── .rspec ├── .rubocop.yml ├── .travis.yml ├── Appraisals ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── bin/ │ └── zapata ├── gemfiles/ │ ├── 5.2.gemfile │ └── 6.0.gemfile ├── lib/ │ ├── zapata/ │ │ ├── analyst.rb │ │ ├── cli.rb │ │ ├── core/ │ │ │ ├── collector.rb │ │ │ ├── loader.rb │ │ │ ├── reader.rb │ │ │ └── writer.rb │ │ ├── core.rb │ │ ├── db.rb │ │ ├── diver.rb │ │ ├── predictor/ │ │ │ ├── args.rb │ │ │ ├── chooser.rb │ │ │ └── value.rb │ │ ├── predictor.rb │ │ ├── primitive/ │ │ │ ├── arg.rb │ │ │ ├── array.rb │ │ │ ├── base.rb │ │ │ ├── basic.rb │ │ │ ├── casgn.rb │ │ │ ├── const.rb │ │ │ ├── const_send.rb │ │ │ ├── def.rb │ │ │ ├── defs.rb │ │ │ ├── hash.rb │ │ │ ├── ivar.rb │ │ │ ├── klass.rb │ │ │ ├── lvar.rb │ │ │ ├── missing.rb │ │ │ ├── modul.rb │ │ │ ├── nil.rb │ │ │ ├── optarg.rb │ │ │ ├── raw.rb │ │ │ ├── send.rb │ │ │ ├── sklass.rb │ │ │ └── var.rb │ │ ├── primitive.rb │ │ ├── printer.rb │ │ ├── rzpec/ │ │ │ ├── runner.rb │ │ │ └── writer.rb │ │ └── version.rb │ └── zapata.rb ├── script/ │ ├── bootstrap │ └── test ├── spec/ │ ├── array_spec.rb │ ├── definition_spec.rb │ ├── generation_spec.rb │ ├── hash_spec.rb │ ├── klass_types_spec.rb │ ├── send_spec.rb │ ├── simple_types_spec.rb │ ├── spec_helper.rb │ └── support/ │ └── rails_test_app/ │ ├── README.md │ ├── Rakefile │ ├── app/ │ │ ├── assets/ │ │ │ ├── config/ │ │ │ │ └── manifest.js │ │ │ ├── images/ │ │ │ │ └── .keep │ │ │ ├── javascripts/ │ │ │ │ └── application.js │ │ │ └── stylesheets/ │ │ │ └── application.css │ │ ├── controllers/ │ │ │ ├── application_controller.rb │ │ │ └── concerns/ │ │ │ └── .keep │ │ ├── helpers/ │ │ │ └── application_helper.rb │ │ ├── mailers/ │ │ │ └── .keep │ │ ├── models/ │ │ │ ├── .keep │ │ │ ├── concerns/ │ │ │ │ └── .keep │ │ │ ├── robot_to_test.rb │ │ │ ├── test_array.rb │ │ │ ├── test_const.rb │ │ │ ├── test_definition.rb │ │ │ ├── test_float.rb │ │ │ ├── test_hash.rb │ │ │ ├── test_int.rb │ │ │ ├── test_send.rb │ │ │ ├── test_str.rb │ │ │ ├── test_sym.rb │ │ │ └── testing_module/ │ │ │ ├── bare.rb │ │ │ ├── klass_methods.rb │ │ │ └── nested/ │ │ │ └── inside.rb │ │ └── views/ │ │ └── layouts/ │ │ └── application.html.erb │ ├── config/ │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments/ │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers/ │ │ │ ├── backtrace_silencers.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales/ │ │ │ └── en.yml │ │ ├── routes.rb │ │ └── secrets.yml │ ├── config.ru │ ├── db/ │ │ └── seeds.rb │ ├── lib/ │ │ ├── assets/ │ │ │ └── .keep │ │ └── tasks/ │ │ └── .keep │ ├── log/ │ │ └── .keep │ ├── public/ │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ └── robots.txt │ └── spec/ │ ├── models/ │ │ ├── robot_to_test_spec.rb │ │ ├── test_array_spec.rb │ │ ├── test_const_spec.rb │ │ ├── test_definition_spec.rb │ │ ├── test_float_spec.rb │ │ ├── test_hash_spec.rb │ │ ├── test_int_spec.rb │ │ ├── test_send_spec.rb │ │ ├── test_str_spec.rb │ │ ├── test_sym_spec.rb │ │ └── testing_module/ │ │ ├── bare_spec.rb │ │ ├── klass_methods_spec.rb │ │ └── nested/ │ │ └── inside_spec.rb │ ├── rails_helper.rb │ └── spec_helper.rb └── zapata.gemspec ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /spec/support/rails_test_app/Gemfile.lock /tmp/ *.bundle *.so *.o *.a mkmf.log .rspec_status gemfiles/*.lock spec/support/rails_test_app/db/*.sqlite3 spec/support/rails_test_app/db/*.sqlite3-journal spec/support/rails_test_app/log/*.log spec/support/rails_test_app/tmp/ ================================================ FILE: .rspec ================================================ --color --warnings --require spec_helper --pattern "spec/*_spec.rb" ================================================ FILE: .rubocop.yml ================================================ AllCops: TargetRubyVersion: 2.3 Exclude: - 'spec/support/rails_test_app/**/*' Style/Documentation: Enabled: false Layout/ParameterAlignment: Enabled: true EnforcedStyle: with_fixed_indentation Layout/MultilineOperationIndentation: Enabled: true EnforcedStyle: indented Layout/MultilineMethodCallIndentation: Enabled: true EnforcedStyle: indented Layout/CaseIndentation: Enabled: true EnforcedStyle: end Layout/EndAlignment: Enabled: true EnforcedStyleAlignWith: variable Style/EmptyMethod: Enabled: false Metrics/BlockLength: Exclude: - 'spec/**/*_spec.rb' - 'zapata.gemspec' ================================================ FILE: .travis.yml ================================================ language: ruby script: script/test rvm: - 2.3.8 - 2.4.8 - 2.5.7 - 2.6.5 - 2.7.0 gemfile: - gemfiles/5.2.gemfile - gemfiles/6.0.gemfile matrix: exclude: - rvm: 2.3.8 gemfile: gemfiles/6.0.gemfile - rvm: 2.4.8 gemfile: gemfiles/6.0.gemfile ================================================ FILE: Appraisals ================================================ # frozen_string_literal: true appraise '5.2' do gem 'rails', '~> 5.2.0' gem 'sqlite3' end appraise '6.0' do gem 'rails', '~> 6.0.0' gem 'sqlite3' end ================================================ FILE: CONTRIBUTING.md ================================================ ## Collaboration :heart: It is encouraged by somehow managing to bring a cake to your house. I promise, I will really try. This is a great project to understand language architecture in general. A project to let your free and expressionistic side shine through by leaving meta hacks and rainbows everywhere. Thank you to everyone who do. I strongly believe that this can make the developer job less robotic and more creative. 1. [Fork it](https://github.com/Nedomas/zapata/fork) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request To install, run: ```sh cd zapata script/bootstrap ``` For specs: ```sh script/test # or bundle exec rspec --pattern "spec/*_spec.rb" ``` ================================================ FILE: Gemfile ================================================ # frozen_string_literal: true source 'https://rubygems.org' # Specify your gem's dependencies in zapata.gemspec group :test do gem 'coveralls', require: false end gemspec ================================================ FILE: LICENSE ================================================ Copyright (c) 2014 Domas MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Zapata Who has time to write tests? This is a revolutionary tool to make them write themselves. [![Gem Version](http://img.shields.io/gem/v/zapata.svg?style=flat)][rubygems] [![Build Status](http://img.shields.io/travis/Nedomas/zapata.svg?style=flat)][travis] [![Dependency Status](http://img.shields.io/gemnasium/Nedomas/zapata.svg?style=flat)][gemnasium] [![Coverage Status](http://img.shields.io/coveralls/Nedomas/zapata/master.svg?style=flat)][coveralls] ![Emiliano Zapata](https://cloud.githubusercontent.com/assets/1877286/3753719/af3bfec2-1814-11e4-8790-242c2b26a8e9.jpg) # What is your problem? There comes a day where you have this bullshit class ``RobotToTest``. We need tests. :shipit: ```ruby class RobotToTest def initialize(human_name, cv) @name = robot_name(human_name) end def robot_name(human_name) "#{self.class.prefix}_#{human_name}" end def cv { planets: planets } end def nested_fun_objects(fun_objects) 'It was fun' end def self.prefix 'Robot' end private def planets ['Mars', Human.home] end def fun_objects [%i(array in array), { hash: nested_hash }] end def nested_hash { in_hash: { in: array } } end def array %w(array) end end # just another class to analyze class Human def initialize human_name = 'Emiliano' end def self.home 'Earth' end end ``` ## Solving it You run ``zapata generate app/models/robot_to_test.rb`` and pop the champagne. Zapata generated ``spec/models/robot_to_test_spec.rb`` for you. ```ruby describe RobotToTest do let(:robot_to_test) do RobotToTest.new('Emiliano', { planets: ['Mars', Human.home] }) end it '#robot_name' do expect(robot_to_test.robot_name('Emiliano')).to eq('Robot_Emiliano') end it '#cv' do expect(robot_to_test.cv).to eq({ planets: ['Mars', 'Earth'] }) end it '#nested_fun_objects' do expect(robot_to_test.nested_fun_objects([ [:array, :in, :array], { hash: { in_hash: { in: ['array'] } } } ])).to eq('It was fun') end it '#prefix' do expect(RobotToTest.prefix).to eq('Robot') end end ``` ## What does it do? It tries to write a passing RSpec spec off the bat. It does fancy analysis to predict the values it could feed to the API of a class. __To be more specific:__ - Analyzes all vars and methods definitions in ``app/models`` - Checks what arguments does a testable method in ``app/models/robot_to_test.rb`` need - Searches for such variable or method name in methods in analyzed - Selects the most probable value by how many times it was repeated in code - Runs the RSpec and fills in the expected values of the test with those returned by RSpec For more things it can currently do check test files https://github.com/Nedomas/zapata/tree/master/spec ## Workflow with Zapata Say you are writing some new feature on your existing project. Before writing that, you probably want to test out the current functionality. But who has time for that? You let *Zapata* create that quick spec for you. Think of it as a *current functionality lock*. Write more code and when you're happy with the result - lock it up again. ## Requirements - Ruby 2.1+ - Rails 3.0+ ## Installation Add `zapata` to your `Gemfile`. It currently only works if the library is added to the `Gemfile`. ```ruby gem 'zapata', groups: %w(development test) ``` ## Usage To use run ```sh zapata generate app/models/model_name.rb ``` To ignore other files and analyze a single model you want to generate a spec for: ```sh zapata generate app/models/model_name.rb --single ``` ## Collaboration :heart: It is encouraged by somehow managing to bring a cake to your house. I promise, I will really try. This is a great project to understand language architecture in general. A project to let your free and expressionistic side shine through by leaving meta hacks and rainbows everywhere. Thank you to everyone who do. I strongly believe that this can make the developer job less robotic and more creative. 1. [Fork it](https://github.com/Nedomas/zapata/fork) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request To install, run: ```sh cd zapata script/bootstrap ``` For specs: ```sh script/test # or bundle exec rspec --pattern "spec/*_spec.rb" ``` ## Awareness I am well aware that this is featured in [Ruby Weekly 223](http://rubyweekly.com/issues/223). On that note I'd like to thank everybody who helped it shine through. Special thanks to my comrade [@jpalumickas](https://github.com/jpalumickas), with whom we share a vision of a better world. Also - thank you [@edgibbs](https://github.com/edgibbs), for being the early contributor. [@morron](https://github.com/morron) - for caring. Huge thanks to [@marcinruszkiewicz](https://github.com/marcinruszkiewicz) for reviving this gem to life in 2019/2020. Also additional thanks to [@jpalumickas](https://github.com/jpalumickas) for all the extra fixes and modernizing the codebase. This would not be done without you all. ## Copyright Copyright (c) 2014-2018 Justas, Andrew, Ed, Dmitry, Domas. See [LICENSE](LICENSE) for details. [rubygems]: https://rubygems.org/gems/zapata [travis]: http://travis-ci.org/Nedomas/zapata [gemnasium]: https://gemnasium.com/Nedomas/zapata [coveralls]: https://coveralls.io/r/Nedomas/zapata [codeclimate]: https://codeclimate.com/github/Nedomas/zapata ================================================ FILE: Rakefile ================================================ # frozen_string_literal: true require 'bundler/gem_tasks' ================================================ FILE: bin/zapata ================================================ #!/usr/bin/env ruby # frozen_string_literal: true require 'rubygems' require 'bundler/setup' require 'zapata' require 'zapata/cli' Zapata::CLI.start(ARGV) ================================================ FILE: gemfiles/5.2.gemfile ================================================ # frozen_string_literal: true # This file was generated by Appraisal source 'https://rubygems.org' gem 'rails', '~> 5.2.0' gem 'sqlite3' group :test do gem 'coveralls', require: false end gemspec path: '../' ================================================ FILE: gemfiles/6.0.gemfile ================================================ # frozen_string_literal: true # This file was generated by Appraisal source 'https://rubygems.org' gem 'rails', '~> 6.0.0' gem 'sqlite3' group :test do gem 'coveralls', require: false end gemspec path: '../' ================================================ FILE: lib/zapata/analyst.rb ================================================ # frozen_string_literal: true module Zapata class Analyst attr_reader :result def self.analyze(filename) code = Core::Reader.parse(filename) analyst = Analyst.new(code) result = analyst.result.dup analyst.clean result end def initialize(code) # class dive Diver.search_for(:klass) Diver.dive(code) # var dive Diver.search_for(:var) Diver.dive(code) # def dive Diver.search_for(:def) Diver.dive(code) # send dive Diver.search_for(:send) Diver.dive(code) @result = DB.all end def clean DB.destroy_all end end end ================================================ FILE: lib/zapata/cli.rb ================================================ # frozen_string_literal: true require 'thor' require_relative 'version' module Zapata class CLI < Thor desc 'generate FILENAME', 'Generate spec file for model' option :single, type: :boolean, desc: 'Skip app/models analysis', aliases: :s def generate(filename) Zapata::Revolutionist.generate_with_friendly_output( filename: filename, single: options[:single] ) end desc 'version', 'Shows zapata version' def version puts "v#{Zapata::VERSION}" end end end ================================================ FILE: lib/zapata/core/collector.rb ================================================ # frozen_string_literal: true module Zapata module Core class Collector def self.expand_dirs_to_files(dirs) dirs.map { |dir| Dir["#{dir}/*.rb"] }.flatten end end end end ================================================ FILE: lib/zapata/core/loader.rb ================================================ # frozen_string_literal: true module Zapata module Core class Loader class << self def spec_dir File.join(Dir.pwd, '/spec') end def rails_helper_path File.expand_path("#{spec_dir}/rails_helper", __FILE__) end def spec_helper_path File.expand_path("#{spec_dir}/spec_helper", __FILE__) end def helper_name if File.exist?("#{rails_helper_path}.rb") 'rails_helper' elsif File.exist?("#{spec_helper_path}.rb") 'spec_helper' else raise 'Was not able to load nor rails_helper, nor spec_helper' end end def full_helper_path paths = { rails_helper: rails_helper_path, spec_helper: spec_helper_path }.freeze paths[helper_name.to_sym] end def load_spec_helper $LOAD_PATH << spec_dir require helper_name.to_s end end end end end ================================================ FILE: lib/zapata/core/reader.rb ================================================ # frozen_string_literal: true module Zapata module Core class Reader def self.parse(filename) plain_text_code = File.open(filename).read Parser::CurrentRuby.parse(plain_text_code) end end end end ================================================ FILE: lib/zapata/core/writer.rb ================================================ # frozen_string_literal: true module Zapata module Core class Writer def initialize(filename) @filename = filename @padding = 0 clean end def clean file = File.open(@filename, 'w') file.write('') file.close end def append_line(line = '') @padding -= 1 if word_exists?(line, 'end') padding_to_use = @padding padding_to_use = 0 if line.empty? file = File.open(@filename, 'ab+') file.puts("#{' ' * padding_to_use}#{line}") file.close @padding += 1 if word_exists?(line, 'do') end def word_exists?(string, word) !!/\b(?:#{word})\b/.match(string) end end end end ================================================ FILE: lib/zapata/core.rb ================================================ # frozen_string_literal: true require_relative 'core/collector' require_relative 'core/loader' require_relative 'core/reader' require_relative 'core/writer' module Zapata module Core end end ================================================ FILE: lib/zapata/db.rb ================================================ # frozen_string_literal: true module Zapata class DB @records = [] @locs = [] class << self def create(record) loc = record.code.loc unless @locs.include?(loc) @records << record @locs << loc record end end def all @records end def destroy_all @records = [] end end end class SaveManager def self.clean(name) name.to_s.delete('@').to_sym end end end ================================================ FILE: lib/zapata/diver.rb ================================================ # frozen_string_literal: true module Zapata RETURN_TYPES = %i[missing raw const_send sym float str int ivar true false const nil].freeze FINAL_TYPES = Zapata::RETURN_TYPES + %i[array hash] DIVE_TYPES = %i[args begin block defined? nth_ref splat kwsplat class block_pass sclass masgn or and irange erange when and return array kwbegin yield while dstr ensure pair].freeze ASSIGN_TYPES = %i[ivasgn lvasgn or_asgn casgn optarg].freeze DEF_TYPES = %i[def defs].freeze HARD_TYPES = %i[if dsym resbody mlhs next self break zsuper super retry rescue match_with_lvasgn case op_asgn regopt regexp].freeze TYPES_BY_SEARCH_FOR = { klass: %i[class], var: ASSIGN_TYPES, def: DEF_TYPES, send: %i[send] }.freeze PRIMITIVE_TYPES = { Def: %i[def], Defs: %i[defs], Send: %i[send], Array: %i[args array], Hash: %i[hash], Ivar: %i[ivar], Lvar: %i[lvar], Klass: %i[class], Sklass: %i[sclass], Modul: %i[module], Const: %i[const], Optarg: %i[optarg], Arg: %i[arg], Basic: RETURN_TYPES, Casgn: %i[casgn], Var: ASSIGN_TYPES }.freeze class Diver class << self attr_accessor :current_moduls, :current_klass, :current_sklass, :access_level def search_for(what) @search_for = what @current_moduls ||= [] end def dive(code) return Primitive::Nil.new unless code if HARD_TYPES.include?(code.type) return Primitive::Raw.new(:missing, :hard_type) end if (klass = primitive_klass(code)) result = klass.new(code) DB.create(result) if search_for_types.include?(code.type) end deeper_dives(code) result || Primitive::Raw.new(:super, nil) end def primitive_klass(code) primitive_type = find_primitive_type(code) return unless primitive_type "Zapata::Primitive::#{primitive_type}".constantize end def find_primitive_type(code) klass_pair = PRIMITIVE_TYPES.detect do |_, types| types.include?(code.type) end return unless klass_pair klass_pair.first end def search_for_types TYPES_BY_SEARCH_FOR[@search_for] end def deeper_dives(code) return unless DIVE_TYPES.include?(code.type) code.to_a.compact.each do |part| dive(part) end end end end end ================================================ FILE: lib/zapata/predictor/args.rb ================================================ # frozen_string_literal: true module Zapata module Predictor class Args class << self def literal(args_node) return unless args_node raw_args = Diver.dive(args_node).to_raw chosen_args = choose_values(raw_args) Printer.print(chosen_args, args: true) end def choose_values(raw_args) case raw_args.type when :array array = raw_args.value.map do |arg| Value.new(arg.value, arg).choose.to_raw end Primitive::Raw.new(:array, array) when :hash hash = raw_args.value.each_with_object({}) do |(rkey, rval), obj| key = Value.new(rkey.value, rkey).choose.to_raw val = Value.new(rval.value, rval).choose.to_raw obj[key] = val end Primitive::Raw.new(:hash, hash) when :int Primitive::Raw.new(:int, raw_args.value) when :missing Primitive::Raw.new(:missing, raw_args.value) when :nil Primitive::Nil.new.to_raw else raise 'Not yet implemented' end end end end end end ================================================ FILE: lib/zapata/predictor/chooser.rb ================================================ # frozen_string_literal: true module Zapata module Predictor class Chooser def initialize(possible_values) @possible_values = possible_values.dup end def by_probability return if @possible_values.empty? by_count end private def by_count group_with_counts(@possible_values).max_by { |_, v| v }.first end def group_with_counts(values) values.each_with_object(Hash.new(0)) do |value, obj| obj[value] += 1 end end end end end ================================================ FILE: lib/zapata/predictor/value.rb ================================================ # frozen_string_literal: true module Zapata module Predictor class Value extend Memoist def initialize(name, finder = nil) @name = name @finder = finder end def choose return Primitive::Raw.new(:nil, nil) if @name.nil? return @finder if @finder && FINAL_TYPES.include?(@finder.type) return Primitive::Raw.new(:super, @name) if possible_values.empty? Chooser.new(possible_values).by_probability end def a_finder?(primitive) return false unless @finder primitive.class == @finder.class && primitive.name == @finder.name end def possible_values Revolutionist.analysis_as_array.select do |element| !a_finder?(element) && element.name == @name end end memoize :possible_values end end end ================================================ FILE: lib/zapata/predictor.rb ================================================ # frozen_string_literal: true require_relative 'predictor/args' require_relative 'predictor/chooser' require_relative 'predictor/value' module Zapata module Predictor end end ================================================ FILE: lib/zapata/primitive/arg.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Arg < Base def node name = @code.to_a.first type = @code.type OpenStruct.new(type: type, name: name, body: @code) end def to_raw chosen_value = Predictor::Value.new(node.name, self).choose.to_raw return_with_super_as_missing(chosen_value, self) end end end end ================================================ FILE: lib/zapata/primitive/array.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Array < Base def node body = @code type = @code.type OpenStruct.new(type: type, body: body) end def to_a value end def to_raw value = node.body.to_a.map do |node| primitive = Diver.dive(node) raw = primitive.to_raw if raw.type == :super predicted = Predictor::Value.new(raw.value).choose.to_raw return_with_super_as_missing(predicted, primitive) else raw end end Raw.new(:array, value) end end end end ================================================ FILE: lib/zapata/primitive/base.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Base attr_accessor :code, :type def initialize(code) @code = code @type = code.type end def name SaveManager.clean(node.name) end def dive_deeper return if RETURN_TYPES.include?(node.type) Diver.dive(node.args) Diver.dive(node.body) end def to_raw Diver.dive(node.body).to_raw end def return_with_super_as_missing(raw, primitive) raw.type == :super ? Missing.new(primitive.name).to_raw : raw end def return_with_missing_as_super(raw, name) raw.type == :missing ? Raw.new(:super, name) : raw end end end end ================================================ FILE: lib/zapata/primitive/basic.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Basic < Base def to_a [value] end def node body = @code type = @code.type OpenStruct.new(type: type, body: body) end def to_raw Raw.new(node.body.type, node.body.to_a.last) end end end end ================================================ FILE: lib/zapata/primitive/casgn.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Casgn < Base def node modul, name, body = @code.to_a type = @code.type OpenStruct.new(type: type, modul: modul, name: name, body: body) end def literal Diver.dive(node.body).literal end end end end ================================================ FILE: lib/zapata/primitive/const.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Const < Basic def node modul, klass = @code.to_a type = @code.type OpenStruct.new(modul: modul, klass: klass, type: type) end def to_raw Raw.new(:const, [node.modul, node.klass].compact.join('::')) end end end end ================================================ FILE: lib/zapata/primitive/const_send.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class ConstSend def initialize(raw_receiver, method_name, args) @raw_receiver = raw_receiver @method_name = method_name @args = args end def node OpenStruct.new(method_name: @method_name, args: @args) end def to_raw Raw.new(:const_send, "#{Printer.print(@raw_receiver)}.#{node.method_name}#{Predictor::Args.literal(node.args)}") end end end end ================================================ FILE: lib/zapata/primitive/def.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Def < Base attr_accessor :klass def initialize(code) @code = code @klass = Diver.current_klass @self = Diver.current_sklass @access_level = Diver.access_level dive_deeper end def self? !!@self end def public? @access_level == :public end def node name, args, body = @code.to_a type = @code.type OpenStruct.new(type: type, name: name, args: args, body: body) end def literal_predicted_args Predictor::Args.literal(node.args) end end end end ================================================ FILE: lib/zapata/primitive/defs.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Defs < Base attr_accessor :klass def initialize(code) @code = code @klass = Diver.current_klass @access_level = Diver.access_level dive_deeper end def self? true end def public? @access_level == :public end def node _, name, args, body = @code.to_a type = @code.type OpenStruct.new(type: type, name: name, args: args, body: body) end def literal_predicted_args Predictor::Args.literal(node.args) end end end end ================================================ FILE: lib/zapata/primitive/hash.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Hash < Base def node body = @code type = @code.type OpenStruct.new(type: type, body: body) end def to_a value.to_a.flatten end def to_raw result = {} node.body.to_a.each do |pair| key_node, value_node = pair.to_a key = Diver.dive(key_node).to_raw value = Diver.dive(value_node).to_raw result[key] = value end Raw.new(:hash, result) end end end end ================================================ FILE: lib/zapata/primitive/ivar.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Ivar < Basic end end end ================================================ FILE: lib/zapata/primitive/klass.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Klass < Base def initialize(code) @code = code @moduls = Diver.current_moduls.dup Diver.access_level = :public Diver.current_klass = self dive_deeper Diver.current_klass = nil end def parent_modul_names @moduls.map { |mod| mod&.name }.compact end def node const, _, body = @code.to_a immediate_modul, klass = const.to_a chain = parent_modul_names + [immediate_modul, klass] name = chain.compact.join('::') type = @code.type OpenStruct.new( type: type, immediate_modul: immediate_modul, klass: klass, name: name, body: body ) end end end end ================================================ FILE: lib/zapata/primitive/lvar.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Lvar < Base def node name = @code.to_a.first type = @code.type OpenStruct.new(type: type, name: name, body: @code) end def to_raw chosen_value = Predictor::Value.new(node.name, self).choose if chosen_value.respond_to?(:node) && chosen_value.node.body == node.body Missing.new(node.name).to_raw else chosen_value.to_raw end end end end end ================================================ FILE: lib/zapata/primitive/missing.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Missing def initialize(name) @name = name end def node OpenStruct.new(type: :missing) end def to_raw Raw.new(:missing, @name) end end end end ================================================ FILE: lib/zapata/primitive/modul.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Modul < Base def initialize(code) @code = code Diver.current_moduls << self dive_deeper Diver.current_moduls.pop end def node const, body = @code.to_a modul, name = const.to_a type = @code.type OpenStruct.new(type: type, modul: modul, name: name, body: body) end end end end ================================================ FILE: lib/zapata/primitive/nil.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Nil < Basic def initialize end def node OpenStruct.new(type: :nil) end def to_raw Raw.new(:nil, nil) end end end end ================================================ FILE: lib/zapata/primitive/optarg.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Optarg < Base def node name, body = @code.to_a type = @code.type OpenStruct.new(type: type, name: name, body: body) end def to_raw Diver.dive(node.body).to_raw end end end end ================================================ FILE: lib/zapata/primitive/raw.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Raw attr_accessor :type, :value def initialize(type, value) @type = type @value = value end def to_raw self end end end end ================================================ FILE: lib/zapata/primitive/send.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Send < Base def initialize(code) super if node.name == :private Diver.access_level = :private elsif node.name == :protected Diver.access_level = :protected elsif node.name == :public Diver.access_level = :public end end def to_a [value] end def node receiver, name, args = @code.to_a type = @code.type OpenStruct.new(type: type, name: name, args: args, receiver: receiver) end def raw_receiver return unless node.receiver Diver.dive(node.receiver).to_raw end def to_raw if raw_receiver && raw_receiver.type == :const ConstSend.new(raw_receiver, node.name, node.args).to_raw else missing_name = if node.receiver Unparser.unparse(code) else node.name end Missing.new(missing_name).to_raw end end end end end ================================================ FILE: lib/zapata/primitive/sklass.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Sklass < Base def initialize(code) @code = code Diver.current_sklass = self dive_deeper Diver.current_sklass = nil end def node _, body = @code.to_a type = @code.type OpenStruct.new(type: type, body: body) end end end end ================================================ FILE: lib/zapata/primitive/var.rb ================================================ # frozen_string_literal: true module Zapata module Primitive class Var < Base def node name, body = @code.to_a type = @code.type OpenStruct.new(type: type, name: name, body: body) end def literal Diver.dive(node.body).literal end def to_raw raw = Diver.dive(node.body).to_raw if raw.type == :super Missing.new(node.name).to_raw else raw end end end end end ================================================ FILE: lib/zapata/primitive.rb ================================================ # frozen_string_literal: true require_relative 'primitive/base' require_relative 'primitive/arg' require_relative 'primitive/array' require_relative 'primitive/basic' require_relative 'primitive/casgn' require_relative 'primitive/const' require_relative 'primitive/const_send' require_relative 'primitive/def' require_relative 'primitive/defs' require_relative 'primitive/hash' require_relative 'primitive/ivar' require_relative 'primitive/klass' require_relative 'primitive/lvar' require_relative 'primitive/missing' require_relative 'primitive/modul' require_relative 'primitive/nil' require_relative 'primitive/optarg' require_relative 'primitive/raw' require_relative 'primitive/send' require_relative 'primitive/sklass' require_relative 'primitive/var' module Zapata module Primitive end end ================================================ FILE: lib/zapata/printer.rb ================================================ # frozen_string_literal: true module Zapata class Printer class << self extend Memoist def print(raw, args: false) type = raw.type result = case type when :const, :send, :int, :const_send, :literal, :float raw.value when :str str(raw) when :sym sym(raw) when :true true when :false false when :array array(raw.value) when :hash hash(raw.value) when :nil 'nil' when :missing missing(raw) when :ivar ivar(raw) else raise "Not yet implemented #{raw}" end args ? argize(result, type) : result end def to_var_name(name) name.to_s.split('::').last.underscore.delete('@') end private def array(given) unnested = given.map { |el| unnest(el) } "[#{unnested.join(', ')}]" end def str(raw) # decide which one to use # "\"#{raw.value}\"" "'#{raw.value}'" end def sym(raw) ":#{raw.value}" end def ivar(raw) RZpec::Writer.ivars << raw to_var_name(raw.value) end def missing(raw) print(Primitive::Raw.new(:str, "Missing \"#{raw.value}\"")) end def argize(value, type) case type when :array value = value[1...-1] when :hash value = value[2...-2] end return unless value.present? "(#{[value].flatten.join(', ')})" end def hash(given) unnested = given.each_with_object({}) do |(key, val), obj| obj[unnest(key)] = unnest(val) end values = unnested.map do |key, val| print_hash_pair(key, val, all_keys_symbols?(unnested)) end "{ #{values.join(', ')} }" end def print_hash_pair(key, val, symbol_keys) symbol_keys ? "#{key[1..-1]}: #{val}" : "#{key} => #{val}" end def all_keys_symbols?(hash) hash.keys.all? do |key| Parser::CurrentRuby.parse(key.to_s).type == :sym end end memoize :all_keys_symbols? def unnest(raw) return raw unless raw.respond_to?(:value) if raw.value.is_a?(Primitive::Raw) print(unnest(raw.value)) else print(raw) end end end end end ================================================ FILE: lib/zapata/rzpec/runner.rb ================================================ # frozen_string_literal: true module Zapata module RZpec class Runner attr_reader :ran def initialize(spec_filename) @spec_filename = spec_filename run # silence { run } end def silence original_stderr = $stderr.dup original_stdout = $stdout.dup $stdout.reopen('/dev/null', 'w') $stdout.reopen('/dev/null', 'w') yield $stderr = original_stderr $stdout = original_stdout end def methodz examples.index_by { |ex| ex['description'].delete('#').to_sym } end def result_message(method_name) methodz[method_name]['exception']['message'] end def expected(method_name) report_lines = result_message(method_name).to_s.split(/\n/) expected_line = report_lines.detect { |line| line.match('got:') } if expected_line clean_expected_line = expected_line[10..-1] if (matches = clean_expected_line.match(/\#\<(.+):(.+)\>/)) "'Returned instance object #{matches[1]}'" else Printer.print(Diver.dive(Parser::CurrentRuby.parse(clean_expected_line)).to_raw) end else "'Exception in RSpec'" end end def run @ran = true @stdin, @stdout, @stderr = Bundler.with_clean_env do Open3.popen3("bundle exec rspec #{@spec_filename} --format j") end end def examples parsed_json_result['examples'] end def parsed_json_result @json ||= JSON.parse(@stdout.readlines.last) end end end end ================================================ FILE: lib/zapata/rzpec/writer.rb ================================================ # frozen_string_literal: true module Zapata module RZpec class Writer class << self attr_accessor :ivars def reset_ivars @ivars = [] end end def initialize(file, _code, subject_analysis, whole_analysis, spec_analysis = nil) self.class.reset_ivars @subject_analysis = subject_analysis @whole_analysis = whole_analysis @spec_analysis = spec_analysis @writer = Core::Writer.new(file) @result = {} write_require klasses.each do |klass| write_class(klass) end self.class.reset_ivars end def write_require @writer.append_line("require '#{Core::Loader.helper_name}'") end def klasses @subject_analysis.select { |obj| obj.is_a?(Primitive::Klass) } end def klass_defs(klass) @subject_analysis.select do |method| [Primitive::Def, Primitive::Defs].include?(method.class) && method.public? && method.klass.name == klass.name end end def initialize_def(klass) klass_defs(klass).detect { |method| method.name == :initialize } end def write_class(klass) @writer.append_line @writer.append_line("describe #{klass.name} do") write_instance_let(klass) klass_defs(klass).each do |primitive_def| write_method(primitive_def) end self.class.ivars.each do |ivar| predicted_value = Predictor::Value.new(ivar.value, ivar).choose literal_predicted_value = Printer.print(predicted_value.to_raw) write_let(ivar.value, literal_predicted_value) end @writer.append_line('end') end def write_instance_let(klass) if initialize_def = initialize_def(klass) write_let_from_initialize(initialize_def) else write_let(klass.name, "#{klass.name}.new") end end def write_let(name, block) @writer.append_line("let(:#{Printer.to_var_name(name)}) do") @writer.append_line(block) @writer.append_line('end') end def write_let_from_initialize(initialize_def) block = "#{initialize_def.klass.name}.new#{initialize_def.literal_predicted_args}" write_let(initialize_def.klass.name, block) end def write_method(primitive_def) return unless primitive_def.node.body return if primitive_def.name == :initialize @writer.append_line @writer.append_line("it '##{primitive_def.name}' do") receiver = if primitive_def.self? primitive_def.klass.name else Printer.to_var_name(primitive_def.klass.name) end @writer.append_line( "expect(#{receiver}.#{primitive_def.name}#{primitive_def.literal_predicted_args}).to eq(#{write_equal(primitive_def.name)})" ) @writer.append_line('end') end def write_equal(method_name) if @spec_analysis Printer.print(Primitive::Raw.new(:literal, @spec_analysis.expected(method_name))) else Printer.print(Primitive::Raw.new(:str, 'Fill this in by hand')) end end end end end ================================================ FILE: lib/zapata/version.rb ================================================ # frozen_string_literal: true module Zapata VERSION = '1.0.0' end ================================================ FILE: lib/zapata.rb ================================================ # frozen_string_literal: true require 'parser/current' require 'unparser' require 'tempfile' require 'rails' require 'open3' require 'rspec' require 'memoist' require_relative 'zapata/core' require_relative 'zapata/predictor' require_relative 'zapata/primitive' require_relative 'zapata/rzpec/runner' require_relative 'zapata/rzpec/writer' require_relative 'zapata/analyst' require_relative 'zapata/diver' require_relative 'zapata/db' require_relative 'zapata/printer' require_relative 'zapata/version' module Zapata class Revolutionist class << self attr_accessor :analysis, :analysis_as_array def generate_with_friendly_output(filename:, single: false) spec_filename = Zapata::Revolutionist.generate(filename: filename, single: single) puts "Its done, comrades. File #{spec_filename} was generated." end def generate(filename:, single: false) dirs = single ? [] : %w[app/models] file_list = Core::Collector.expand_dirs_to_files(dirs) new(file_list).generate_rspec_for(filename, spec_filename(filename)) end def init_analysis_as_array @analysis_as_array = analysis.values.flatten end def spec_filename(filename) filename.gsub('app/', 'spec/').gsub('.rb', '_spec.rb') end private def single?(opts, args) opts.single? || args.include?('-s') || args.include?('--single') end end def initialize(file_list) Core::Loader.load_spec_helper self.class.analysis = analyze_multiple(file_list) end def analyze_multiple(files) total = files.size.to_s files.each_with_object({}).with_index do |(filename, obj), i| puts "[#{adjusted_current(i, total)}/#{total}] Analyzing: #{filename}" obj[filename] = Analyst.analyze(filename) end end def adjusted_current(index, total) (index + 1).to_s.rjust(total.size) end def generate_rspec_for(filename, spec_filename) unless self.class.analysis[filename] self.class.analysis[filename] = Analyst.analyze(filename) end self.class.init_analysis_as_array code = Core::Reader.parse(filename) global_analysis = Revolutionist.analysis_as_array # first run Tempfile.open('spec') do |tempfile| RZpec::Writer.new(tempfile.path, code, self.class.analysis[filename], global_analysis) save_spec_file(tempfile.path, spec_filename) spec_analysis = RZpec::Runner.new(spec_filename) # second run with RSpec results RZpec::Writer.new(tempfile.path, code, self.class.analysis[filename], global_analysis, spec_analysis) save_spec_file(tempfile.path, spec_filename) end end def save_spec_file(tmp_spec_filename, spec_filename) spec_path = "#{Dir.pwd}/#{spec_filename}" spec_dir = spec_path.split('/')[0...-1].join('/') FileUtils.mkdir_p(spec_dir) FileUtils.cp(tmp_spec_filename, spec_path) spec_filename end end end ================================================ FILE: script/bootstrap ================================================ #!/usr/bin/env bash set -e rake install cd spec/support/rails_test_app bundle update cd ../../.. echo 'Run specs with:' echo './script/test' ================================================ FILE: script/test ================================================ #!/usr/bin/env bash set -e bundle exec rspec --pattern "spec/*_spec.rb" ================================================ FILE: spec/array_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do before(:all) do @generated = exec_generation('app/models/test_array.rb') end it '#test_in_arg' do has_block('#test_in_arg', %{ expect(test_array.test_in_arg([2, 7.1, 8])).to eq([2, 7.1, 8]) }) end it '#test_nested_one_level' do has_block('#test_nested_one_level', %{ expect(test_array.test_nested_one_level([[2, 7.1, 8], :mexico])).to eq([[2, 7.1, 8], :mexico]) }) end it '#test_nested_two_levels' do has_block('#test_nested_two_levels', %{ expect(test_array.test_nested_two_levels([[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico])).to eq([[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico]) }) end it '#test_nested_three_levels' do has_block('#test_nested_three_levels', %{ expect(test_array.test_nested_three_levels([[[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico], [[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico])).to eq([[[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico], [[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico]) }) end it '#test_hash_nested' do has_block('#test_hash_nested', %{ expect(test_array.test_hash_nested([{ emiliano: [2, 7.1, 8] }])).to eq([{ emiliano: [2, 7.1, 8] }]) }) end end ================================================ FILE: spec/definition_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do before(:all) do @generated = exec_generation('app/models/test_definition.rb') end it '#in_optional_args' do has_block('#in_optional_args', %{ expect(test_definition.in_optional_args(:audioslave)).to eq(:audioslave) }) end it '#use_optional' do has_block('#use_optional', %{ expect(test_definition.use_optional(:audioslave)).to eq(:audioslave) }) end # it '#var_in_optional_args' do # has_block('#var_in_optional_args', %Q{ # expect(test_definition.var_in_optional_args('Chuck')).to eq('Chuck') # }) # end # it '#method_in_optional_args' do # has_block('#method_in_optional_args', %Q{ # expect(test_definition.method_in_optional_args('I am falling')).to eq('I am falling') # }) # end it '#call_method_result_in_optional_args' do has_block('#call_method_result_in_optional_args', %{ expect(test_definition.call_method_result_in_optional_args('Missing "fall_meth.first"')).to eq('Missing "fall_meth.first"') }) end it '#resursive_method' do has_block('#recursive_method', %{ expect(test_definition.recursive_method).to eq('Exception in RSpec') }) end end ================================================ FILE: spec/generation_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do describe '#generate_with_friendly_output' do let(:file_name) { 'app/models/test_array.rb' } context 'with the generate command' do context 'with single specified' do it 'returns a single file generation message' do output = execution_output("cd #{RAILS_TEST_APP_DIR} && bundle exec zapata generate #{file_name} -s") expect(output.count).to eq 1 expect(output.first).to eq "Its done, comrades. File spec/models/test_array_spec.rb was generated.\n" end end context 'with no single specified' do it 'returns mulptile files generation messages' do output = execution_output("cd #{RAILS_TEST_APP_DIR} && bundle exec zapata generate #{file_name}") expect(output.count).to be > 1 end end end end end ================================================ FILE: spec/hash_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do before(:all) do @generated = exec_generation('app/models/test_hash.rb') end it '#test_in_arg' do has_block('#test_in_arg', %{ expect(test_hash.test_in_arg({ 1 => :one, TestHash => 2.718 })).to eq({ 1 => :one, TestHash => 2.718 }) }) end it '#test_nested_one_level' do has_block('#test_nested_one_level', %{ expect(test_hash.test_nested_one_level({ first_level: { 1 => :one, TestHash => 2.718 } })).to eq({ first_level: { 1 => :one, TestHash => 2.718 } }) }) end it '#test_nested_two_levels' do has_block('#test_nested_two_levels', %{ expect(test_hash.test_nested_two_levels({ second_level: { first_level: { 1 => :one, TestHash => 2.718 } } })).to eq({ second_level: { first_level: { 1 => :one, TestHash => 2.718 } } }) }) end it '#test_nested_three_levels' do has_block('#test_nested_three_levels', %{ expect(test_hash.test_nested_three_levels({ third_level: { second_level: { first_level: { 1 => :one, TestHash => 2.718 } } } })).to eq({ third_level: { second_level: { first_level: { 1 => :one, TestHash => 2.718 } } } }) }) end it '#test_key_as_another_hash' do has_block('#test_key_as_another_hash', %{ expect(test_hash.test_key_as_another_hash({ { 1 => :one, TestHash => 2.718 } => :ratm })).to eq({ { 1 => :one, TestHash => 2.718 } => :ratm }) }) end it '#test_keys_are_symbols' do has_block('#test_keys_are_symbols', %{ expect(test_hash.test_keys_are_symbols({ this: 'should', be: 'pretty' })).to eq({ be: 'pretty', this: 'should' }) }) end end ================================================ FILE: spec/klass_types_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do context 'it should work with' do it 'bare module' do generated = exec_generation('app/models/testing_module/bare.rb') expected = expected(%{require 'rails_helper' describe TestingModule::Bare do let(:bare) do TestingModule::Bare.new end end}) expect(generated).to eq(expected) end it 'nested module' do generated = exec_generation('app/models/testing_module/nested/inside.rb') expected = expected(%{require 'rails_helper' describe TestingModule::Nested::Inside do let(:inside) do TestingModule::Nested::Inside.new end end}) expect(generated).to eq(expected) end context 'klass methods' do before(:all) do @generated = exec_generation('app/models/testing_module/klass_methods.rb') end it '#defined_with_self' do has_block('#defined_with_self', %{ expect(TestingModule::KlassMethods.defined_with_self(5)).to eq(5) }) end it '#defined_with_back_back_self' do has_block('#defined_with_back_back_self', %{ expect(TestingModule::KlassMethods.defined_with_back_back_self(5)).to eq(5) }) end it '#back_to_public_defined_with_self' do has_block('#back_to_public_defined_with_self', %{ expect(TestingModule::KlassMethods.back_to_public_defined_with_self(5)).to eq(5) }) end end end end ================================================ FILE: spec/send_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do before(:all) do @generated = exec_generation('app/models/test_send.rb') end it '#another_method_as_arg' do has_block('#another_method_as_arg', %{ expect(test_send.another_method_as_arg('Help method')).to eq('Help method') }) end # it '#second_level_method_chain' do # has_block('#second_level_method_chain', %Q{ # expect(test_send.second_level_method_chain('Help method')).to eq('Help method') # }) # end # it '#third_level_method_chain' do # has_block('#third_level_method_chain', %Q{ # expect(test_send.third_level_method_chain('Help method')).to eq('Help method') # }) # end # it '#method_with_calculated_value' do # has_block('#method_with_calculated_value', %Q{ # expect(test_send.method_with_calculated_value('Missing "calculated_value"')).to eq('Missing "calculated_value"') # }) # end it '#to_another_object' do has_block('#to_another_object', %{ expect(test_send.to_another_object(AnotherObject.my_name)).to eq('Domas') }) end it '#to_another_object_with_params' do has_block('#to_another_object_with_params', %{ expect(test_send.to_another_object_with_params(AnotherObject.send_with_params(12))).to eq('Id was 12') }) end it '#not_explicit_with_params' do has_block('#not_explicit_with_params', %{ expect(test_send.not_explicit_with_params('Could you find it?')).to eq('Could you find it?') }) end it '#fail_to_understand' do has_block('#fail_to_understand', %{ expect(test_send.fail_to_understand('Missing "failure"')).to eq('Missing "failure"') }) end end ================================================ FILE: spec/simple_types_spec.rb ================================================ # frozen_string_literal: true describe Zapata::Revolutionist do context 'it should work with' do it 'ints' do generated = exec_generation('app/models/test_int.rb') expected = expected(%{require 'rails_helper' describe TestInt do let(:test_int) do TestInt.new end it '#test_int_in_arg' do expect(test_int.test_int_in_arg(1)).to eq(1) end end}) expect(generated).to eq(expected) end it 'symbols' do generated = exec_generation('app/models/test_sym.rb') expected = expected(%{require 'rails_helper' describe TestSym do let(:test_sym) do TestSym.new end it '#test_sym_in_arg' do expect(test_sym.test_sym_in_arg(:rock)).to eq(:rock) end end}) expect(generated).to eq(expected) end it 'strings' do generated = exec_generation('app/models/test_str.rb') expected = expected(%{require 'rails_helper' describe TestStr do let(:test_str) do TestStr.new end it '#test_str_in_arg' do expect(test_str.test_str_in_arg('audioslave')).to eq('audioslave') end end}) expect(generated).to eq(expected) end it 'floats' do generated = exec_generation('app/models/test_float.rb') expected = expected(%{require 'rails_helper' describe TestFloat do let(:test_float) do TestFloat.new end it '#test_float_in_arg' do expect(test_float.test_float_in_arg(2.718)).to eq(2.718) end end}) expect(generated).to eq(expected) end it 'consts' do generated = exec_generation('app/models/test_const.rb') expected = expected(%{require 'rails_helper' describe TestConst do let(:test_const) do TestConst.new end it '#test_const_in_arg' do expect(test_const.test_const_in_arg(TestConst)).to eq(TestConst) end end}) expect(generated).to eq(expected) end end end ================================================ FILE: spec/spec_helper.rb ================================================ # frozen_string_literal: true require 'coveralls' Coveralls.wear! require 'zapata' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = '.rspec_status' config.expect_with :rspec do |c| c.syntax = :expect end end # Helper methods RAILS_TEST_APP_DIR = "#{Dir.pwd}/spec/support/rails_test_app" def execution_output(command) stdout = Bundler.with_clean_env do Open3.pipeline_r( command ) end stdout.first.readlines end def clean(string) string.split(/\n/).map(&:strip).join("\n") end def expected(code) clean( <<-EXPECTED #{code} EXPECTED ) end def exec_generation(generate_for) _, stdout, stderr = Bundler.with_clean_env do Open3.popen3( "cd #{RAILS_TEST_APP_DIR} && bundle exec zapata generate #{generate_for} -s" ) end output = stdout.readlines begin generated_filename = output.last.match(/File\ (.+)\ was/)[1] rescue StandardError raise "Did not get the message that file was generated. Got this instead: STDOUT: #{output} STDERR: #{stderr.readlines}" end spec_path = "#{RAILS_TEST_APP_DIR}/#{generated_filename}" clean( <<-ACTUAL #{File.read(spec_path)} ACTUAL ) end def has_block(name, expected_content) generated_lines = @generated.split("\n") it_starts = generated_lines.index { |line| line == "it '#{name}' do" } raise 'No such block' unless it_starts might_match_lines = generated_lines[it_starts..-1] it_ends = might_match_lines.index { |line| line == 'end' } block = might_match_lines[1...it_ends].first expect(block).to eq(expected_content.strip) end ================================================ FILE: spec/support/rails_test_app/README.md ================================================ # Zapata Rails test Just a testing app for [Zapata gem](https://github.com/Nedomas/zapata) ================================================ FILE: spec/support/rails_test_app/Rakefile ================================================ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) Rails.application.load_tasks ================================================ FILE: spec/support/rails_test_app/app/assets/config/manifest.js ================================================ //= link_tree ../images //= link_directory ../javascripts .js //= link_directory ../stylesheets .css ================================================ FILE: spec/support/rails_test_app/app/assets/images/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/app/assets/javascripts/application.js ================================================ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details // about supported directives. // //= require jquery //= require jquery_ujs //= require turbolinks //= require_tree . ================================================ FILE: spec/support/rails_test_app/app/assets/stylesheets/application.css ================================================ /* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any styles * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * *= require_tree . *= require_self */ ================================================ FILE: spec/support/rails_test_app/app/controllers/application_controller.rb ================================================ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception end ================================================ FILE: spec/support/rails_test_app/app/controllers/concerns/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/app/helpers/application_helper.rb ================================================ module ApplicationHelper end ================================================ FILE: spec/support/rails_test_app/app/mailers/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/app/models/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/app/models/concerns/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/app/models/robot_to_test.rb ================================================ class RobotToTest def initialize(human_name, _cv) @name = robot_name(human_name) end def robot_name(human_name) "#{self.class.prefix}_#{human_name}" end def cv { planets: planets } end def nested_fun_objects(_fun_objects) 'It was fun' end def self.prefix 'Robot' end private def planets ['Mars', Human.home] end def fun_objects [%i[array in array], { hash: nested_hash }] end def nested_hash { in_hash: { in: array } } end def array %w[array] end end class Human def initialize human_name = 'Emiliano' end def self.home 'Earth' end end ================================================ FILE: spec/support/rails_test_app/app/models/test_array.rb ================================================ class TestArray def initialize end def test_in_arg(numbers_array) numbers_array end def test_nested_one_level(nested_one_level) nested_one_level end def test_nested_two_levels(nested_two_levels) nested_two_levels end def test_nested_three_levels(nested_three_levels) nested_three_levels end def test_hash_nested(hash_nested) hash_nested end private def data_to_analyze numbers_array = [2, 7.1, 8] nested_one_level = [numbers_array, :mexico] nested_two_levels = [nested_one_level, numbers_array, :mexico] nested_three_levels = [nested_two_levels, nested_one_level, numbers_array, :mexico] hash_nested = [{ emiliano: numbers_array }] end end ================================================ FILE: spec/support/rails_test_app/app/models/test_const.rb ================================================ class TestConst def initialize end def test_const_in_arg(const) const end private def data_to_analyze const = TestConst end end ================================================ FILE: spec/support/rails_test_app/app/models/test_definition.rb ================================================ class TestDefinition def in_optional_args(optional = :audioslave) optional end def use_optional(optional) optional end def var_in_optional_args(optional_var = fallback) optional_var end def method_in_optional_args(optional_method = fall_meth) optional_method end def call_method_result_in_optional_args(complex_method = fall_meth.first) complex_method end def should_not_show_empty_method end def recursive_method recursive_method end private def fall_meth 'I am falling' end def data_to_analyze fallback = 'Chuck' end end ================================================ FILE: spec/support/rails_test_app/app/models/test_float.rb ================================================ class TestFloat def initialize end def test_float_in_arg(float) float end private def data_to_analyze float = 2.718 end end ================================================ FILE: spec/support/rails_test_app/app/models/test_hash.rb ================================================ class TestHash def initialize end def test_in_arg(hash) hash end def test_nested_one_level(one_level_nested_hash) one_level_nested_hash end def test_nested_two_levels(two_levels_nested_hash) two_levels_nested_hash end def test_nested_three_levels(three_levels_nested_hash) three_levels_nested_hash end def test_key_as_another_hash(key_as_another_hash) key_as_another_hash end def test_keys_are_symbols(pretty_hash) pretty_hash end private def data_to_analyze hash = { 1 => :one, TestHash => 2.718 } one_level_nested_hash = { first_level: hash } two_levels_nested_hash = { second_level: one_level_nested_hash } three_levels_nested_hash = { third_level: two_levels_nested_hash } key_as_another_hash = { hash => :ratm } pretty_hash = { this: 'should', be: 'pretty' } end end ================================================ FILE: spec/support/rails_test_app/app/models/test_int.rb ================================================ class TestInt def initialize end def test_int_in_arg(int) int end private def data_to_analyze int = 1 end end ================================================ FILE: spec/support/rails_test_app/app/models/test_send.rb ================================================ class TestSend def another_method_as_arg(help_method) help_method end def second_level_method_chain(second_level_method) second_level_method end def third_level_method_chain(third_level_method) third_level_method end def method_with_calculated_value(calculated_value) calculated_value end def to_another_object(another_object_method) another_object_method end def to_another_object_with_params(send_with_params) send_with_params end def not_explicit_with_params(not_explicit) not_explicit end def fail_to_understand(failure) failure end private def help_method 'Help method' end def second_level_method help_method end def third_level_method second_level_method end def calculated_value 1 + 3 end def not_explicit(_name) 'Could you find it?' end def failure(name) # does not understand :dstr "Can't you understand, #{name}?" end def data_to_analyze another_object_method = AnotherObject.my_name send_with_params = AnotherObject.send_with_params(12) end end class AnotherObject def self.my_name 'Domas' end def self.send_with_params(id) "Id was #{id}" end end ================================================ FILE: spec/support/rails_test_app/app/models/test_str.rb ================================================ class TestStr def initialize end def test_str_in_arg(str) str end private def data_to_analyze str = 'audioslave' end end ================================================ FILE: spec/support/rails_test_app/app/models/test_sym.rb ================================================ class TestSym def initialize end def test_sym_in_arg(sym) sym end private def data_to_analyze sym = :rock end end ================================================ FILE: spec/support/rails_test_app/app/models/testing_module/bare.rb ================================================ module TestingModule class Bare def initialize end end end ================================================ FILE: spec/support/rails_test_app/app/models/testing_module/klass_methods.rb ================================================ module TestingModule class KlassMethods def self.defined_with_self(klass_methods_int) klass_methods_int end class << self def defined_with_back_back_self(klass_methods_int) klass_methods_int end end private class << self def privately_defined_with_back_back_self(klass_methods_int) klass_methods_int end end def self.privately_defined_with_self(klass_methods_int) klass_methods_int end protected class << self def protectedly_defined_with_back_back_self(klass_methods_int) klass_methods_int end end def self.protectedly_defined_with_self(klass_methods_int) klass_methods_int end def data_to_analyze klass_methods_int = 5 end public def self.back_to_public_defined_with_self(klass_methods_int) klass_methods_int end end end ================================================ FILE: spec/support/rails_test_app/app/models/testing_module/nested/inside.rb ================================================ module TestingModule module Nested class Inside def initialize end end end end ================================================ FILE: spec/support/rails_test_app/app/views/layouts/application.html.erb ================================================ ZapataRailsTest <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> <%= yield %> ================================================ FILE: spec/support/rails_test_app/config/application.rb ================================================ require File.expand_path('../boot', __FILE__) require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module RailsTestApp class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de end end ================================================ FILE: spec/support/rails_test_app/config/boot.rb ================================================ # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) ================================================ FILE: spec/support/rails_test_app/config/database.yml ================================================ # SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' # default: &default adapter: sqlite3 pool: 5 timeout: 5000 development: <<: *default database: db/development.sqlite3 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: db/test.sqlite3 production: <<: *default database: db/production.sqlite3 ================================================ FILE: spec/support/rails_test_app/config/environment.rb ================================================ # Load the Rails application. require File.expand_path('../application', __FILE__) # Initialize the Rails application. Rails.application.initialize! ================================================ FILE: spec/support/rails_test_app/config/environments/development.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Do not eager load code on boot. config.eager_load = false # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true # Raises error for missing translations # config.action_view.raise_on_missing_translations = true end ================================================ FILE: spec/support/rails_test_app/config/environments/production.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or nginx will already do this). config.serve_static_assets = false # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Generate digests for assets URLs. config.assets.digest = true # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # Set to :debug to see everything in the log. config.log_level = :info # Prepend all log lines with the following tags. # config.log_tags = [ :subdomain, :uuid ] # Use a different logger for distributed setups. # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production. # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # config.assets.precompile += %w( search.js ) # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify # Disable automatic flushing of the log to improve performance. # config.autoflush_log = false # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false end ================================================ FILE: spec/support/rails_test_app/config/environments/test.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. config.eager_load = false # Configure static asset server for tests with Cache-Control for performance. config.serve_static_assets = true config.static_cache_control = 'public, max-age=3600' # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr # Raises error for missing translations # config.action_view.raise_on_missing_translations = true end ================================================ FILE: spec/support/rails_test_app/config/initializers/backtrace_silencers.rb ================================================ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! ================================================ FILE: spec/support/rails_test_app/config/initializers/cookies_serializer.rb ================================================ # Be sure to restart your server when you modify this file. Rails.application.config.action_dispatch.cookies_serializer = :json ================================================ FILE: spec/support/rails_test_app/config/initializers/filter_parameter_logging.rb ================================================ # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. Rails.application.config.filter_parameters += [:password] ================================================ FILE: spec/support/rails_test_app/config/initializers/inflections.rb ================================================ # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections # are locale specific, and you may define rules for as many different # locales as you wish. All of these examples are active by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' # end ================================================ FILE: spec/support/rails_test_app/config/initializers/mime_types.rb ================================================ # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf ================================================ FILE: spec/support/rails_test_app/config/initializers/session_store.rb ================================================ # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_zapata_rails_test_session' ================================================ FILE: spec/support/rails_test_app/config/initializers/wrap_parameters.rb ================================================ # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] if respond_to?(:wrap_parameters) end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = true # end ================================================ FILE: spec/support/rails_test_app/config/locales/en.yml ================================================ # Files in the config/locales directory are used for internationalization # and are automatically loaded by Rails. If you want to use locales other # than English, add the necessary files in this directory. # # To use the locales, use `I18n.t`: # # I18n.t 'hello' # # In views, this is aliased to just `t`: # # <%= t('hello') %> # # To use a different locale, set it with `I18n.locale`: # # I18n.locale = :es # # This would use the information in config/locales/es.yml. # # To learn more, please read the Rails Internationalization guide # available at http://guides.rubyonrails.org/i18n.html. en: hello: "Hello world" ================================================ FILE: spec/support/rails_test_app/config/routes.rb ================================================ Rails.application.routes.draw do # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". # You can have the root of your site routed with "root" # root 'welcome#index' # Example of regular route: # get 'products/:id' => 'catalog#view' # Example of named route that can be invoked with purchase_url(id: product.id) # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase # Example resource route (maps HTTP verbs to controller actions automatically): # resources :products # Example resource route with options: # resources :products do # member do # get 'short' # post 'toggle' # end # # collection do # get 'sold' # end # end # Example resource route with sub-resources: # resources :products do # resources :comments, :sales # resource :seller # end # Example resource route with more complex sub-resources: # resources :products do # resources :comments # resources :sales do # get 'recent', on: :collection # end # end # Example resource route with concerns: # concern :toggleable do # post 'toggle' # end # resources :posts, concerns: :toggleable # resources :photos, concerns: :toggleable # Example resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController # # (app/controllers/admin/products_controller.rb) # resources :products # end end ================================================ FILE: spec/support/rails_test_app/config/secrets.yml ================================================ # Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. # Make sure the secrets in this file are kept private # if you're sharing your code publicly. development: secret_key_base: ef3f44bcc760cb4d0ffae8aba6eb815bb51ffce6282871b327adf69b91efde6e910ebf2994950d0514c97cb2f98db71e7e49144b870357c744ed3066b12d1c5a test: secret_key_base: beeab7b99b31e2b533f1b9ff126857f637fc83b50efa4e33c87dcfcd9c90b99ea29b128fc0074f028b1b639c1330efe37fd40e25a1c98dfaa0151c2638b2a334 # Do not keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> ================================================ FILE: spec/support/rails_test_app/config.ru ================================================ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run Rails.application ================================================ FILE: spec/support/rails_test_app/db/seeds.rb ================================================ # This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) ================================================ FILE: spec/support/rails_test_app/lib/assets/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/lib/tasks/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/log/.keep ================================================ ================================================ FILE: spec/support/rails_test_app/public/404.html ================================================ The page you were looking for doesn't exist (404)

The page you were looking for doesn't exist.

You may have mistyped the address or the page may have moved.

If you are the application owner check the logs for more information.

================================================ FILE: spec/support/rails_test_app/public/422.html ================================================ The change you wanted was rejected (422)

The change you wanted was rejected.

Maybe you tried to change something you didn't have access to.

If you are the application owner check the logs for more information.

================================================ FILE: spec/support/rails_test_app/public/500.html ================================================ We're sorry, but something went wrong (500)

We're sorry, but something went wrong.

If you are the application owner check the logs for more information.

================================================ FILE: spec/support/rails_test_app/public/robots.txt ================================================ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file # # To ban all spiders from the entire site uncomment the next two lines: # User-agent: * # Disallow: / ================================================ FILE: spec/support/rails_test_app/spec/models/robot_to_test_spec.rb ================================================ require 'rails_helper' describe RobotToTest do let(:robot_to_test) do RobotToTest.new('Emiliano', planets: ['Mars', Human.home]) end it '#robot_name' do expect(robot_to_test.robot_name('Emiliano')).to eq('Robot_Emiliano') end it '#cv' do expect(robot_to_test.cv).to eq(planets: %w(Mars Earth)) end it '#nested_fun_objects' do expect(robot_to_test.nested_fun_objects([[:array, :in, :array], { hash: { in_hash: { in: ['array'] } } }])).to eq('It was fun') end it '#prefix' do expect(RobotToTest.prefix).to eq('Robot') end end describe Human do let(:human) do Human.new end it '#home' do expect(Human.home).to eq('Earth') end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_array_spec.rb ================================================ require 'rails_helper' describe TestArray do let(:test_array) do TestArray.new end it '#test_in_arg' do expect(test_array.test_in_arg([2, 7.1, 8])).to eq([2, 7.1, 8]) end it '#test_nested_one_level' do expect(test_array.test_nested_one_level([[2, 7.1, 8], :mexico])).to eq([[2, 7.1, 8], :mexico]) end it '#test_nested_two_levels' do expect(test_array.test_nested_two_levels([[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico])).to eq([[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico]) end it '#test_nested_three_levels' do expect(test_array.test_nested_three_levels([[[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico], [[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico])).to eq([[[[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico], [[2, 7.1, 8], :mexico], [2, 7.1, 8], :mexico]) end it '#test_hash_nested' do expect(test_array.test_hash_nested([{ emiliano: [2, 7.1, 8] }])).to eq([{ emiliano: [2, 7.1, 8] }]) end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_const_spec.rb ================================================ require 'rails_helper' describe TestConst do let(:test_const) do TestConst.new end it '#test_const_in_arg' do expect(test_const.test_const_in_arg(TestConst)).to eq(TestConst) end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_definition_spec.rb ================================================ require 'rails_helper' describe TestDefinition do let(:test_definition) do TestDefinition.new end it '#in_optional_args' do expect(test_definition.in_optional_args(:audioslave)).to eq(:audioslave) end it '#use_optional' do expect(test_definition.use_optional(:audioslave)).to eq(:audioslave) end it '#var_in_optional_args' do expect(test_definition.var_in_optional_args('Missing "fallback"')).to eq('Missing "fallback"') end it '#method_in_optional_args' do expect(test_definition.method_in_optional_args('Missing "fall_meth"')).to eq('Missing "fall_meth"') end it '#call_method_result_in_optional_args' do expect(test_definition.call_method_result_in_optional_args('Missing "fall_meth.first"')).to eq('Missing "fall_meth.first"') end it '#recursive_method' do expect(test_definition.recursive_method).to eq('Exception in RSpec') end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_float_spec.rb ================================================ require 'rails_helper' describe TestFloat do let(:test_float) do TestFloat.new end it '#test_float_in_arg' do expect(test_float.test_float_in_arg(2.718)).to eq(2.718) end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_hash_spec.rb ================================================ require 'rails_helper' describe TestHash do let(:test_hash) do TestHash.new end it '#test_in_arg' do expect(test_hash.test_in_arg({ 1 => :one, TestHash => 2.718 })).to eq({ 1 => :one, TestHash => 2.718 }) end it '#test_nested_one_level' do expect(test_hash.test_nested_one_level({ first_level: { 1 => :one, TestHash => 2.718 } })).to eq({ first_level: { 1 => :one, TestHash => 2.718 } }) end it '#test_nested_two_levels' do expect(test_hash.test_nested_two_levels({ second_level: { first_level: { 1 => :one, TestHash => 2.718 } } })).to eq({ second_level: { first_level: { 1 => :one, TestHash => 2.718 } } }) end it '#test_nested_three_levels' do expect(test_hash.test_nested_three_levels({ third_level: { second_level: { first_level: { 1 => :one, TestHash => 2.718 } } } })).to eq({ third_level: { second_level: { first_level: { 1 => :one, TestHash => 2.718 } } } }) end it '#test_key_as_another_hash' do expect(test_hash.test_key_as_another_hash({ { 1 => :one, TestHash => 2.718 } => :ratm })).to eq({ { 1 => :one, TestHash => 2.718 } => :ratm }) end it '#test_keys_are_symbols' do expect(test_hash.test_keys_are_symbols({ this: 'should', be: 'pretty' })).to eq({ be: 'pretty', this: 'should' }) end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_int_spec.rb ================================================ require 'rails_helper' describe TestInt do let(:test_int) do TestInt.new end it '#test_int_in_arg' do expect(test_int.test_int_in_arg(1)).to eq(1) end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_send_spec.rb ================================================ require 'rails_helper' describe TestSend do let(:test_send) do TestSend.new end it '#another_method_as_arg' do expect(test_send.another_method_as_arg('Help method')).to eq('Help method') end it '#second_level_method_chain' do expect(test_send.second_level_method_chain('Missing "help_method"')).to eq('Missing "help_method"') end it '#third_level_method_chain' do expect(test_send.third_level_method_chain('Missing "second_level_method"')).to eq('Missing "second_level_method"') end it '#method_with_calculated_value' do expect(test_send.method_with_calculated_value('Missing "1 + 3"')).to eq('Missing "1 + 3"') end it '#to_another_object' do expect(test_send.to_another_object(AnotherObject.my_name)).to eq('Domas') end it '#to_another_object_with_params' do expect(test_send.to_another_object_with_params(AnotherObject.send_with_params(12))).to eq('Id was 12') end it '#not_explicit_with_params' do expect(test_send.not_explicit_with_params('Could you find it?')).to eq('Could you find it?') end it '#fail_to_understand' do expect(test_send.fail_to_understand('Missing "failure"')).to eq('Missing "failure"') end end describe AnotherObject do let(:another_object) do AnotherObject.new end it '#my_name' do expect(AnotherObject.my_name).to eq('Domas') end it '#send_with_params' do expect(AnotherObject.send_with_params('Missing "id"')).to eq('Id was Missing "id"') end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_str_spec.rb ================================================ require 'rails_helper' describe TestStr do let(:test_str) do TestStr.new end it '#test_str_in_arg' do expect(test_str.test_str_in_arg('audioslave')).to eq('audioslave') end end ================================================ FILE: spec/support/rails_test_app/spec/models/test_sym_spec.rb ================================================ require 'rails_helper' describe TestSym do let(:test_sym) do TestSym.new end it '#test_sym_in_arg' do expect(test_sym.test_sym_in_arg(:rock)).to eq(:rock) end end ================================================ FILE: spec/support/rails_test_app/spec/models/testing_module/bare_spec.rb ================================================ require 'rails_helper' describe TestingModule::Bare do let(:bare) do TestingModule::Bare.new end end ================================================ FILE: spec/support/rails_test_app/spec/models/testing_module/klass_methods_spec.rb ================================================ require 'rails_helper' describe TestingModule::KlassMethods do let(:klass_methods) do TestingModule::KlassMethods.new end it '#defined_with_self' do expect(TestingModule::KlassMethods.defined_with_self(5)).to eq(5) end it '#defined_with_back_back_self' do expect(TestingModule::KlassMethods.defined_with_back_back_self(5)).to eq(5) end it '#back_to_public_defined_with_self' do expect(TestingModule::KlassMethods.back_to_public_defined_with_self(5)).to eq(5) end end ================================================ FILE: spec/support/rails_test_app/spec/models/testing_module/nested/inside_spec.rb ================================================ require 'rails_helper' describe TestingModule::Nested::Inside do let(:inside) do TestingModule::Nested::Inside.new end end ================================================ FILE: spec/support/rails_test_app/spec/rails_helper.rb ================================================ # This file is copied to spec/ when you run 'rails generate rspec:install' ENV['RAILS_ENV'] ||= 'test' require 'spec_helper' require File.expand_path('../../config/environment', __FILE__) require 'rspec/rails' # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are # run as spec files by default. This means that files in spec/support that end # in _spec.rb will both be required and run as specs, causing the specs to be # run twice. It is recommended that you do not name files matching this glob to # end with _spec.rb. You can configure this pattern with the --pattern # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } # Checks for pending migrations before tests are run. # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.maintain_test_schema! RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. config.use_transactional_fixtures = true # RSpec Rails can automatically mix in different behaviours to your tests # based on their file location, for example enabling you to call `get` and # `post` in specs under `spec/controllers`. # # You can disable this behaviour by removing the line below, and instead # explicitly tag your specs with their type, e.g.: # # RSpec.describe UsersController, type: :controller do # # ... # end # # The different available types are documented in the features, such as in # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! end ================================================ FILE: spec/support/rails_test_app/spec/spec_helper.rb ================================================ # This file was generated by the `rails generate rspec:install` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # The generated `.rspec` file contains `--require spec_helper` which will cause this # file to always be loaded, without a need to explicitly require it in any files. # # Given that it is always loaded, you are encouraged to keep this file as # light-weight as possible. Requiring heavyweight dependencies from this file # will add to the boot time of your test suite on EVERY test run, even for an # individual file that may not need all of that loaded. Instead, make a # separate helper file that requires this one and then use it only in the specs # that actually need it. # # The `.rspec` file also contains a few flags that are not defaults but that # users commonly want. # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration RSpec.configure do |config| # The settings below are suggested to provide a good initial experience # with RSpec, but feel free to customize to your heart's content. # # These two settings work together to allow you to limit a spec run # # to individual examples or groups you care about by tagging them with # # `:focus` metadata. When nothing is tagged with `:focus`, all examples # # get run. # config.filter_run :focus # config.run_all_when_everything_filtered = true # # # Many RSpec users commonly either run the entire suite or an individual # # file, and it's useful to allow more verbose output when running an # # individual spec file. # if config.files_to_run.one? # # Use the documentation formatter for detailed output, # # unless a formatter has already been configured # # (e.g. via a command-line flag). # config.default_formatter = 'doc' # end # # # Print the 10 slowest examples and example groups at the # # end of the spec run, to help surface which specs are running # # particularly slow. # config.profile_examples = 10 # # # Run specs in random order to surface order dependencies. If you find an # # order dependency and want to debug it, you can fix the order by providing # # the seed, which is printed after each run. # # --seed 1234 # config.order = :random # # # Seed global randomization in this process using the `--seed` CLI option. # # Setting this allows you to use `--seed` to deterministically reproduce # # test failures related to randomization by passing the same `--seed` value # # as the one that triggered the failure. # Kernel.srand config.seed # # # rspec-expectations config goes here. You can use an alternate # # assertion/expectation library such as wrong or the stdlib/minitest # # assertions if you prefer. # config.expect_with :rspec do |expectations| # # Enable only the newer, non-monkey-patching expect syntax. # # For more details, see: # # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax # expectations.syntax = :expect # end # # # rspec-mocks config goes here. You can use an alternate test double # # library (such as bogus or mocha) by changing the `mock_with` option here. # config.mock_with :rspec do |mocks| # # Enable only the newer, non-monkey-patching expect syntax. # # For more details, see: # # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ # mocks.syntax = :expect # # # Prevents you from mocking or stubbing a method that does not exist on # # a real object. This is generally recommended. # mocks.verify_partial_doubles = true # end end ================================================ FILE: zapata.gemspec ================================================ # frozen_string_literal: true lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'zapata/version' Gem::Specification.new do |spec| spec.name = 'zapata' spec.version = Zapata::VERSION spec.authors = ['Domas Bitvinskas'] spec.email = ['domas.bitvinskas@me.com'] spec.summary = 'Automatic automated test writer' spec.description = 'Who has time to write tests? This is a revolutional ' \ 'tool to make them write themselves.' spec.homepage = 'https://github.com/Nedomas/zapata' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0") spec.executables = ['zapata'] spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.add_runtime_dependency 'memoist', '~> 0.16' spec.add_runtime_dependency 'parser' spec.add_runtime_dependency 'rails' spec.add_runtime_dependency 'rspec' spec.add_runtime_dependency 'rspec-rails' spec.add_runtime_dependency 'thor' spec.add_runtime_dependency 'unparser' spec.add_development_dependency 'appraisal', '~> 2.2' spec.add_development_dependency 'pry' spec.add_development_dependency 'rake' spec.add_development_dependency 'rubocop', '~> 0.80' spec.add_development_dependency 'sqlite3' end