├── .codeclimate.yml ├── .gitignore ├── .hound.yml ├── .rubocop.yml ├── .travis.yml ├── CHANGELOG.md ├── Cheffile ├── Cheffile.lock ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── Vagrantfile ├── active_mocker.gemspec ├── bin └── console ├── codeclimate.yml ├── example_rails_app ├── .gitignore ├── .rspec ├── Gemfile ├── README.rdoc ├── Rakefile ├── app │ ├── assets │ │ ├── images │ │ │ └── .keep │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css │ ├── controllers │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── mailers │ │ └── .keep │ ├── models │ │ ├── .keep │ │ ├── comment.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── subscription.rb │ │ └── user.rb │ └── views │ │ └── layouts │ │ └── application.html.erb ├── bin │ ├── bundle │ ├── rails │ ├── rake │ └── spring ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── assets.rb │ │ ├── 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 ├── db │ ├── migrate │ │ ├── 20140731143902_create_users.rb │ │ ├── 20140731143955_create_comments.rb │ │ └── 20140731144123_create_subscriptions.rb │ ├── schema.rb │ └── seeds.rb ├── example_rails_app.iml ├── lib │ ├── assets │ │ └── .keep │ ├── subscribe_user.rb │ └── tasks │ │ └── .keep ├── log │ └── .keep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── favicon.ico │ └── robots.txt ├── spec │ ├── lib │ │ └── subscribe_user_spec.rb │ ├── mocks │ │ ├── comment_mock.rb │ │ ├── subscription_mock.rb │ │ └── user_mock.rb │ ├── rails_helper.rb │ └── spec_helper.rb └── vendor │ └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep ├── lib ├── active_mocker.rb └── active_mocker │ ├── attribute.rb │ ├── attribute_types │ ├── enum.rb │ └── register.rb │ ├── config.rb │ ├── display_errors.rb │ ├── error_object.rb │ ├── file_path_to_ruby_class.rb │ ├── file_writer.rb │ ├── generate.rb │ ├── hash_new_style.rb │ ├── inspectable.rb │ ├── inspectable │ ├── bigdecimal.rb │ ├── date.rb │ ├── dir.rb │ ├── file.rb │ ├── pathname.rb │ ├── struct.rb │ └── time.rb │ ├── late_inclusion.rb │ ├── loaded_mocks.rb │ ├── loaded_mocks │ └── features.rb │ ├── mock.rb │ ├── mock │ ├── alias_attribute.rb │ ├── association.rb │ ├── base.rb │ ├── belongs_to.rb │ ├── collection.rb │ ├── compatibility │ │ ├── base │ │ │ └── ar51.rb │ │ └── queries │ │ │ └── ar52.rb │ ├── do_nothing_active_record_methods.rb │ ├── exceptions.rb │ ├── has_and_belongs_to_many.rb │ ├── has_many.rb │ ├── has_one.rb │ ├── hash_process.rb │ ├── mock_relation.rb │ ├── mockable_method.rb │ ├── object_inspect.rb │ ├── queries.rb │ ├── records.rb │ ├── relation.rb │ ├── single_relation.rb │ ├── template_methods.rb │ └── unrepresentable_const_value.rb │ ├── mock_creator.rb │ ├── mock_creator │ ├── associations.rb │ ├── attributes.rb │ ├── class_methods.rb │ ├── defined_methods.rb │ ├── mock_build_version.rb │ ├── modules_constants.rb │ ├── recreate_class_method_calls.rb │ ├── safe_methods.rb │ └── scopes.rb │ ├── mock_template.erb │ ├── mock_template │ ├── _associations.erb │ ├── _attributes.erb │ ├── _class_methods.erb │ ├── _defined_methods.erb │ ├── _mock_build_version.erb │ ├── _modules_constants.erb │ ├── _recreate_class_method_calls.erb │ └── _scopes.erb │ ├── null_progress.rb │ ├── parent_class.rb │ ├── progress.rb │ ├── public_methods.rb │ ├── railtie.rb │ ├── rspec.rb │ ├── rspec_helper.rb │ ├── task.rake │ ├── template_creator.rb │ └── version.rb ├── log └── .keep ├── spec ├── gemfile_version_match_spec.rb ├── lib │ ├── active_mocker │ │ ├── config_spec.rb │ │ ├── display_errors_spec.rb │ │ ├── file_path_to_ruby_class_spec.rb │ │ ├── generate_spec.rb │ │ ├── loaded_mocks_spec.rb │ │ ├── mock │ │ │ ├── association_spec.rb │ │ │ ├── base_spec.rb │ │ │ ├── belongs_to_spec.rb │ │ │ ├── collection_spec.rb │ │ │ ├── has_and_belongs_to_many_spec.rb │ │ │ ├── has_many_shared_example.rb │ │ │ ├── has_many_spec.rb │ │ │ ├── hash_process_spec.rb │ │ │ ├── queriable_shared_example.rb │ │ │ ├── records_spec.rb │ │ │ └── relation_spec.rb │ │ ├── mock_creator_spec.rb │ │ ├── parent_class_spec.rb │ │ └── template_creator_spec.rb │ ├── model_nested.rb │ ├── models │ │ ├── model.rb │ │ ├── non_active_record_model.rb │ │ └── some_namespace │ │ │ └── some_module.rb │ ├── person.rb │ └── post_methods.rb ├── spec_helper.rb ├── support │ └── strip_heredoc.rb └── unit_logger.rb ├── tasks ├── integration.rake ├── setup.rake └── unit.rake └── test_rails_app ├── .secret ├── Appraisals ├── Gemfile ├── LICENSE ├── Rakefile ├── app └── models │ ├── .keep │ ├── account.rb │ ├── api │ └── customer.rb │ ├── child_model.rb │ ├── has_no_parent.rb │ ├── has_no_table.rb │ ├── identity.rb │ ├── micropost.rb │ ├── micropost │ └── core.rb │ ├── relationship.rb │ └── user.rb ├── bin ├── bundle ├── rails ├── rake └── rspec ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── secret_token.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml └── routes.rb ├── db ├── migrate │ └── 20160621215939_create_products.rb ├── schema.rb └── seeds.rb ├── gemfiles ├── rails_4.2.gemfile ├── rails_4.2.gemfile.lock ├── rails_5.2.gemfile ├── rails_5.2.gemfile.lock ├── rails_6.0.gemfile └── rails_6.0.gemfile.lock ├── lib ├── post_methods.rb └── unit_logger.rb ├── log └── .keep ├── spec ├── account_spec.rb ├── active_record_compatible_api.rb ├── api │ └── customer_spec.rb ├── child_model_spec.rb ├── clear_after_all_example_spec.rb ├── const_stub_example_spec.rb ├── factories.rb ├── features_spec.rb ├── has_no_table_spec.rb ├── idenity_mock_spec.rb ├── micropost_mock_spec.rb ├── rails_helper.rb ├── rake_task_spec.rb ├── relation_spec.rb ├── spec_helper.rb ├── user_mock_spec.rb └── user_spec.rb └── test_rails_4_app.iml /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | csslint: 4 | enabled: false 5 | duplication: 6 | enabled: true 7 | config: 8 | languages: 9 | - ruby 10 | eslint: 11 | enabled: false 12 | fixme: 13 | enabled: true 14 | rubocop: 15 | enabled: true 16 | ratings: 17 | paths: 18 | - "**.erb" 19 | - "**.rb" 20 | exclude_paths: 21 | - spec/ 22 | - test_rails_app/ 23 | - example_rails_app/ 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | sample_app_rails_4/log/* 19 | log/active_mocker.log 20 | test_rails_app/db/development.sqlite3 21 | test_rails_app/log/* 22 | test_rails_app/.idea/* 23 | example_rails_app/.idea/* 24 | .idea/* 25 | cookbooks/* 26 | .vagrant/* 27 | test_rails_app/spec/mocks/* 28 | *.sqlite3 29 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | ruby: 2 | config_file: .rubocop.yml 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.3 3 | DisplayStyleGuide: true 4 | Exclude: 5 | - spec/**/*.rb 6 | - test_rails_app/**/*.rb 7 | Rails: 8 | Enabled: true 9 | 10 | 11 | Metrics/LineLength: 12 | Max: 120 13 | 14 | Layout/AlignParameters: 15 | # Alignment of parameters in multi-line method calls. 16 | # 17 | # The `with_first_parameter` style aligns the following lines along the same 18 | # column as the first parameter. 19 | # 20 | # method_call(a, 21 | # b) 22 | # 23 | # The `with_fixed_indentation` style aligns the following lines with one 24 | # level of indentation relative to the start of the line with the method call. 25 | # 26 | # method_call(a, 27 | # b) 28 | EnforcedStyle: with_first_parameter 29 | SupportedStyles: 30 | - with_first_parameter 31 | - with_fixed_indentation 32 | 33 | # Multi-line method chaining should be done with trailing dots. 34 | Style/DotPosition: 35 | EnforcedStyle: leading 36 | SupportedStyles: 37 | - leading 38 | 39 | Style/Documentation: 40 | Description: 'Document classes and non-namespace modules.' 41 | Enabled: false 42 | Exclude: 43 | - 'spec/**/*' 44 | - 'test/**/*' 45 | 46 | Style/TrailingCommaInArguments: 47 | # If `comma`, the cop requires a comma after the last argument, but only for 48 | # parenthesized method calls where each argument is on its own line. 49 | # If `consistent_comma`, the cop requires a comma after the last argument, 50 | # for all parenthesized method calls with arguments. 51 | EnforcedStyleForMultiline: comma 52 | SupportedStyles: 53 | - comma 54 | - consistent_comma 55 | - no_comma 56 | Style/TrailingCommaInArrayLiteral: 57 | # If `comma`, the cop requires a comma after the last item in an array or 58 | # hash, but only when each item is on its own line. 59 | # If `consistent_comma`, the cop requires a comma after the last item of all 60 | # non-empty array and hash literals. 61 | EnforcedStyleForMultiline: comma 62 | SupportedStyles: 63 | - comma 64 | - consistent_comma 65 | - no_comma 66 | Style/TrailingCommaInHashLiteral: 67 | # If `comma`, the cop requires a comma after the last item in an array or 68 | # hash, but only when each item is on its own line. 69 | # If `consistent_comma`, the cop requires a comma after the last item of all 70 | # non-empty array and hash literals. 71 | EnforcedStyleForMultiline: comma 72 | SupportedStyles: 73 | - comma 74 | - consistent_comma 75 | - no_comma 76 | 77 | Style/StringLiterals: 78 | EnforcedStyle: double_quotes 79 | SupportedStyles: 80 | - single_quotes 81 | - double_quotes 82 | # If true, strings which span multiple lines using \ for continuation must 83 | # use the same type of quotes on each line. 84 | ConsistentQuotesInMultiline: false 85 | 86 | Style/StringLiteralsInInterpolation: 87 | EnforcedStyle: double_quotes 88 | SupportedStyles: 89 | - single_quotes 90 | - double_quotes 91 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.4.7 4 | - 2.5.5 5 | - 2.6.4 6 | gemfile: 7 | - test_rails_app/gemfiles/rails_4.2.gemfile 8 | - test_rails_app/gemfiles/rails_5.2.gemfile 9 | - test_rails_app/gemfiles/rails_6.0.gemfile 10 | env: 11 | global: 12 | TRAVIS: true 13 | sudo: false 14 | cache: bundler 15 | CODECLIMATE_REPO_TOKEN: 11158e372b49d660cd14d15f351b0326e7bcdd29e7e31f271a2055530212f3e3 16 | matrix: 17 | exclude: 18 | - rvm: 2.4.7 19 | gemfile: test_rails_app/gemfiles/rails_6.0.gemfile 20 | -------------------------------------------------------------------------------- /Cheffile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | site "http://community.opscode.com/api/v1" 5 | 6 | cookbook "apt" 7 | cookbook "build-essential", {} 8 | cookbook "rvm", :github => "fnichol/chef-rvm", :ref => "v0.9.0", "rubies" => ["2.1.7", "2.2.3"] 9 | cookbook "sqlite", {} 10 | cookbook "git", {} 11 | -------------------------------------------------------------------------------- /Cheffile.lock: -------------------------------------------------------------------------------- 1 | SITE 2 | remote: http://community.opscode.com/api/v1 3 | specs: 4 | apt (2.8.2) 5 | build-essential (2.2.4) 6 | chef_handler (1.2.0) 7 | dmg (2.2.2) 8 | git (4.3.4) 9 | build-essential (>= 0.0.0) 10 | dmg (>= 0.0.0) 11 | windows (>= 0.0.0) 12 | yum-epel (>= 0.0.0) 13 | sqlite (1.1.2) 14 | windows (1.38.2) 15 | chef_handler (>= 0.0.0) 16 | yum (3.8.1) 17 | yum-epel (0.6.3) 18 | yum (~> 3.2) 19 | 20 | GIT 21 | remote: https://github.com/fnichol/chef-rvm 22 | ref: v0.9.0 23 | sha: 4a408e5d6c5a52c37388a799c516430263339849 24 | specs: 25 | rvm (0.9.0) 26 | 27 | DEPENDENCIES 28 | apt (>= 0) 29 | build-essential (>= 0) 30 | git (>= 0) 31 | rvm (>= 0) 32 | sqlite (>= 0) 33 | 34 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | gem "rails" 4 | gem "sqlite3" 5 | gem "appraisal" 6 | 7 | group :development, :test do 8 | gem "rspec" 9 | gem "rspec-rails" 10 | end 11 | gem "codeclimate-test-reporter", require: nil 12 | # Specify your gem's dependencies in active_mocker.gemspec 13 | gemspec 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dustin Zeisler 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rubygems" 3 | require "bundler/setup" 4 | require "bundler/gem_tasks" 5 | Dir.glob("tasks/*.rake").each { |r| import r } 6 | 7 | task default: "specs" 8 | 9 | desc "run setup and tests" 10 | task :specs do 11 | Rake::Task["setup"].invoke 12 | Rake::Task["unit"].invoke 13 | Rake::Task["integration"].invoke 14 | end 15 | 16 | desc "run tests" 17 | task :test do 18 | if ENV["TRAVIS"] 19 | require "codeclimate-test-reporter" 20 | CodeClimate::TestReporter.start 21 | end 22 | 23 | Rake::Task["unit"].invoke 24 | Rake::Task["integration"].invoke 25 | end 26 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | # This file originally created at http://rove.io/70b9e033e9d63eea7548469647e3efd3 4 | 5 | # -*- mode: ruby -*- 6 | # vi: set ft=ruby : 7 | 8 | Vagrant.configure("2") do |config| 9 | config.vm.box = "opscode-ubuntu-12.04_chef-11.4.0" 10 | config.vm.box_url = "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_chef-11.4.0.box" 11 | config.ssh.forward_agent = true 12 | 13 | config.vm.network :forwarded_port, guest: 3000, host: 3000 14 | 15 | config.vm.provision :chef_solo do |chef| 16 | chef.cookbooks_path = ["cookbooks"] 17 | chef.add_recipe :apt 18 | chef.add_recipe "rvm::vagrant" 19 | chef.add_recipe "rvm::system" 20 | chef.add_recipe "sqlite" 21 | chef.add_recipe "git" 22 | chef.json = { 23 | git: { 24 | prefix: "/usr/local", 25 | }, 26 | } 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /active_mocker.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # frozen_string_literal: true 3 | lib = File.expand_path("../lib", __FILE__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require "active_mocker/version" 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = "active_mocker" 9 | spec.version = ActiveMocker::VERSION 10 | spec.authors = ["Dustin Zeisler"] 11 | spec.email = ["dustin@zeisler.net"] 12 | spec.summary = "Creates stub classes from any ActiveRecord model" 13 | spec.description = "Creates stub classes from any ActiveRecord model. By using stubs in your tests you don't need to load Rails or the database, sometimes resulting in a 10x speed improvement. ActiveMocker analyzes the methods and database columns to generate a Ruby class file. The stub file can be run standalone and comes included with many useful parts of ActiveRecord. Stubbed out methods contain their original argument signatures or ActiveMocker friendly code can be brought over in its entirety. Mocks are regenerated when the schema is modified so your mocks won't go stale, preventing the case where your unit tests pass but production code fails." 14 | spec.homepage = "https://github.com/zeisler/active_mocker" 15 | spec.license = "MIT" 16 | 17 | spec.files = Dir["CHANGELOG.md", "LICENSE.txt", "README.md", "lib/**/*"] 18 | 19 | spec.require_paths = ["lib"] 20 | 21 | spec.required_ruby_version = ">= 2.3" 22 | 23 | spec.add_runtime_dependency "activesupport", ">= 4.2" 24 | spec.add_runtime_dependency "virtus", "~> 1.0" 25 | spec.add_runtime_dependency "ruby-progressbar", "~> 1.7" 26 | spec.add_runtime_dependency "colorize", "~> 0.7", ">= 0.7" 27 | spec.add_runtime_dependency "rake", ">= 10.0" 28 | spec.add_runtime_dependency "reverse_parameters", "~> 1.1", ">= 1.1.1" 29 | spec.add_runtime_dependency "active_record_schema_scrapper", "~> 0.8" 30 | spec.add_runtime_dependency "dissociated_introspection", "~> 0.8", ">= 0.8.4" 31 | 32 | spec.add_development_dependency "bundler", "~> 1.10" 33 | spec.add_development_dependency "rubocop", "~> 0.49.0" 34 | spec.add_development_dependency "rspec", "~> 3.4" 35 | end 36 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "active_mocker" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start 16 | -------------------------------------------------------------------------------- /codeclimate.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | Ruby: true 3 | exclude_paths: 4 | - sample_app_rails_4/**/* 5 | - test_rails_app/**/* 6 | - spec/**/* 7 | -------------------------------------------------------------------------------- /example_rails_app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/*.log 16 | /tmp 17 | -------------------------------------------------------------------------------- /example_rails_app/.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --warnings 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /example_rails_app/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | gem "rails", "~>4.2" 4 | gem "sqlite3" 5 | group :development, :test do 6 | # gem 'active_mocker', '~>1.7' 7 | gem "active_mocker", path: "../" 8 | gem "rspec-rails", "~> 3.0" 9 | end 10 | -------------------------------------------------------------------------------- /example_rails_app/README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /example_rails_app/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path("../config/application", __FILE__) 6 | 7 | Rails.application.load_tasks 8 | -------------------------------------------------------------------------------- /example_rails_app/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/app/assets/images/.keep -------------------------------------------------------------------------------- /example_rails_app/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /example_rails_app/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /example_rails_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class ApplicationController < ActionController::Base 3 | # Prevent CSRF attacks by raising an exception. 4 | # For APIs, you may want to use :null_session instead. 5 | protect_from_forgery with: :exception 6 | end 7 | -------------------------------------------------------------------------------- /example_rails_app/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /example_rails_app/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ApplicationHelper 3 | end 4 | -------------------------------------------------------------------------------- /example_rails_app/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/app/mailers/.keep -------------------------------------------------------------------------------- /example_rails_app/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/app/models/.keep -------------------------------------------------------------------------------- /example_rails_app/app/models/comment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class Comment < ActiveRecord::Base 3 | belongs_to :user 4 | end 5 | -------------------------------------------------------------------------------- /example_rails_app/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/app/models/concerns/.keep -------------------------------------------------------------------------------- /example_rails_app/app/models/subscription.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class Subscription < ActiveRecord::Base 3 | belongs_to :user 4 | end 5 | -------------------------------------------------------------------------------- /example_rails_app/app/models/user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class User < ActiveRecord::Base 3 | has_many :comments 4 | has_many :subscriptions 5 | end 6 | -------------------------------------------------------------------------------- /example_rails_app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ExampleRailsApp 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example_rails_app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) 4 | load Gem.bin_path("bundler", "bundle") 5 | -------------------------------------------------------------------------------- /example_rails_app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | begin 4 | load File.expand_path("../spring", __FILE__) 5 | rescue LoadError 6 | end 7 | APP_PATH = File.expand_path("../../config/application", __FILE__) 8 | require_relative "../config/boot" 9 | require "rails/commands" 10 | -------------------------------------------------------------------------------- /example_rails_app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | begin 4 | load File.expand_path("../spring", __FILE__) 5 | rescue LoadError 6 | end 7 | require_relative "../config/boot" 8 | require "rake" 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /example_rails_app/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # This file loads spring without using Bundler, in order to be fast 5 | # It gets overwritten when you run the `spring binstub` command 6 | 7 | unless defined?(Spring) 8 | require "rubygems" 9 | require "bundler" 10 | 11 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m) 12 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) 13 | ENV["GEM_HOME"] = "" 14 | Gem.paths = ENV 15 | 16 | gem "spring", match[1] 17 | require "spring/binstub" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /example_rails_app/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file is used by Rack-based servers to start the application. 3 | 4 | require ::File.expand_path("../config/environment", __FILE__) 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /example_rails_app/config/application.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../boot", __FILE__) 3 | 4 | require "rails/all" 5 | 6 | # Require the gems listed in Gemfile, including any gems 7 | # you've limited to :test, :development, or :production. 8 | Bundler.require(*Rails.groups) 9 | 10 | module ExampleRailsApp 11 | class Application < Rails::Application 12 | # Settings in config/environments/* take precedence over those specified here. 13 | # Application configuration should go into files in config/initializers 14 | # -- all .rb files in that directory are automatically loaded. 15 | 16 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 17 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 18 | # config.time_zone = 'Central Time (US & Canada)' 19 | 20 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 21 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 22 | # config.i18n.default_locale = :de 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /example_rails_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Set up gems listed in the Gemfile. 3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) 4 | 5 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) 6 | -------------------------------------------------------------------------------- /example_rails_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /example_rails_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Load the Rails application. 3 | require File.expand_path("../application", __FILE__) 4 | 5 | # Initialize the Rails application. 6 | Rails.application.initialize! 7 | -------------------------------------------------------------------------------- /example_rails_app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | Rails.application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # In the development environment your application's code is reloaded on 6 | # every request. This slows down response time but is perfect for development 7 | # since you don't have to restart the web server when you make code changes. 8 | config.cache_classes = false 9 | 10 | # Do not eager load code on boot. 11 | config.eager_load = false 12 | 13 | # Show full error reports and disable caching. 14 | config.consider_all_requests_local = true 15 | config.action_controller.perform_caching = false 16 | 17 | # Don't care if the mailer can't send. 18 | config.action_mailer.raise_delivery_errors = false 19 | 20 | # Print deprecation notices to the Rails logger. 21 | config.active_support.deprecation = :log 22 | 23 | # Raise an error on page load if there are pending migrations. 24 | config.active_record.migration_error = :page_load 25 | 26 | # Debug mode disables concatenation and preprocessing of assets. 27 | # This option may cause significant delays in view rendering with a large 28 | # number of complex assets. 29 | config.assets.debug = true 30 | 31 | # Adds additional error checking when serving assets at runtime. 32 | # Checks for improperly declared sprockets dependencies. 33 | # Raises helpful error messages. 34 | config.assets.raise_runtime_errors = true 35 | 36 | # Raises error for missing translations 37 | # config.action_view.raise_on_missing_translations = true 38 | end 39 | -------------------------------------------------------------------------------- /example_rails_app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | Rails.application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # Code is not reloaded between requests. 6 | config.cache_classes = true 7 | 8 | # Eager load code on boot. This eager loads most of Rails and 9 | # your application in memory, allowing both threaded web servers 10 | # and those relying on copy on write to perform better. 11 | # Rake tasks automatically ignore this option for performance. 12 | config.eager_load = true 13 | 14 | # Full error reports are disabled and caching is turned on. 15 | config.consider_all_requests_local = false 16 | config.action_controller.perform_caching = true 17 | 18 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 19 | # Add `rack-cache` to your Gemfile before enabling this. 20 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable Rails's static asset server (Apache or nginx will already do this). 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # `config.assets.precompile` has moved to config/initializers/assets.rb 36 | 37 | # Specifies the header that your server uses for sending files. 38 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 39 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 40 | 41 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 42 | # config.force_ssl = true 43 | 44 | # Set to :debug to see everything in the log. 45 | config.log_level = :info 46 | 47 | # Prepend all log lines with the following tags. 48 | # config.log_tags = [ :subdomain, :uuid ] 49 | 50 | # Use a different logger for distributed setups. 51 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 52 | 53 | # Use a different cache store in production. 54 | # config.cache_store = :mem_cache_store 55 | 56 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 57 | # config.action_controller.asset_host = "http://assets.example.com" 58 | 59 | # Precompile additional assets. 60 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 61 | # config.assets.precompile += %w( search.js ) 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Disable automatic flushing of the log to improve performance. 75 | # config.autoflush_log = false 76 | 77 | # Use default logging formatter so that PID and timestamp are not suppressed. 78 | config.log_formatter = ::Logger::Formatter.new 79 | 80 | # Do not dump schema after migrations. 81 | config.active_record.dump_schema_after_migration = false 82 | end 83 | -------------------------------------------------------------------------------- /example_rails_app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | Rails.application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # The test environment is used exclusively to run your application's 6 | # test suite. You never need to work with it otherwise. Remember that 7 | # your test database is "scratch space" for the test suite and is wiped 8 | # and recreated between test runs. Don't rely on the data there! 9 | config.cache_classes = true 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure static asset server for tests with Cache-Control for performance. 17 | # Show full error reports and disable caching. 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates. 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment. 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Print deprecation notices to the stderr. 33 | config.active_support.deprecation = :stderr 34 | 35 | # Raises error for missing translations 36 | # config.action_view.raise_on_missing_translations = true 37 | end 38 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Version of your assets, change this if you want to expire all your assets. 5 | Rails.application.config.assets.version = "1.0" 6 | 7 | # Precompile additional assets. 8 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 9 | # Rails.application.config.assets.precompile += %w( search.js ) 10 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 6 | 7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 8 | # Rails.backtrace_cleaner.remove_silencers! 9 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | Rails.application.config.action_dispatch.cookies_serializer = :json 5 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Configure sensitive parameters which will be filtered from the log file. 5 | Rails.application.config.filter_parameters += [:password] 6 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new inflection rules using the following format. Inflections 5 | # are locale specific, and you may define rules for as many different 6 | # locales as you wish. All of these examples are active by default: 7 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 8 | # inflect.plural /^(ox)$/i, '\1en' 9 | # inflect.singular /^(ox)en/i, '\1' 10 | # inflect.irregular 'person', 'people' 11 | # inflect.uncountable %w( fish sheep ) 12 | # end 13 | 14 | # These inflection rules are supported but not enabled by default: 15 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 16 | # inflect.acronym 'RESTful' 17 | # end 18 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new mime types for use in respond_to blocks: 5 | # Mime::Type.register "text/richtext", :rtf 6 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | Rails.application.config.session_store :cookie_store, key: "_example_rails_app_session" 5 | -------------------------------------------------------------------------------- /example_rails_app/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # This file contains settings for ActionController::ParamsWrapper which 5 | # is enabled by default. 6 | 7 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 8 | ActiveSupport.on_load(:action_controller) do 9 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 10 | end 11 | 12 | # To enable root element in JSON for ActiveRecord objects. 13 | # ActiveSupport.on_load(:active_record) do 14 | # self.include_root_in_json = true 15 | # end 16 | -------------------------------------------------------------------------------- /example_rails_app/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /example_rails_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | Rails.application.routes.draw do 3 | # The priority is based upon order of creation: first created -> highest priority. 4 | # See how all your routes lay out with "rake routes". 5 | 6 | # You can have the root of your site routed with "root" 7 | # root 'welcome#index' 8 | 9 | # Example of regular route: 10 | # get 'products/:id' => 'catalog#view' 11 | 12 | # Example of named route that can be invoked with purchase_url(id: product.id) 13 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 14 | 15 | # Example resource route (maps HTTP verbs to controller actions automatically): 16 | # resources :products 17 | 18 | # Example resource route with options: 19 | # resources :products do 20 | # member do 21 | # get 'short' 22 | # post 'toggle' 23 | # end 24 | # 25 | # collection do 26 | # get 'sold' 27 | # end 28 | # end 29 | 30 | # Example resource route with sub-resources: 31 | # resources :products do 32 | # resources :comments, :sales 33 | # resource :seller 34 | # end 35 | 36 | # Example resource route with more complex sub-resources: 37 | # resources :products do 38 | # resources :comments 39 | # resources :sales do 40 | # get 'recent', on: :collection 41 | # end 42 | # end 43 | 44 | # Example resource route with concerns: 45 | # concern :toggleable do 46 | # post 'toggle' 47 | # end 48 | # resources :posts, concerns: :toggleable 49 | # resources :photos, concerns: :toggleable 50 | 51 | # Example resource route within a namespace: 52 | # namespace :admin do 53 | # # Directs /admin/products/* to Admin::ProductsController 54 | # # (app/controllers/admin/products_controller.rb) 55 | # resources :products 56 | # end 57 | end 58 | -------------------------------------------------------------------------------- /example_rails_app/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: a2dc302bb4671539b54a76a4d96189a12465ea63b2acb2ebf570e5ae90c0af60621d1dae0937eb16f011f97a6dc27a356cae450cd0d1ecea6b5226542c7392cb 15 | 16 | test: 17 | secret_key_base: 4ee7095421864869816c474292a05a760647f06468a3363fdf9a1f41387d9787e058264c8da775f1ed80bf603dbe64ef58cd5dbf26b51cf09109c678a5ca3b50 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /example_rails_app/db/migrate/20140731143902_create_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class CreateUsers < ActiveRecord::Migration 3 | def change 4 | create_table :users do |t| 5 | t.string :name 6 | t.integer :age 7 | t.boolean :admin 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /example_rails_app/db/migrate/20140731143955_create_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class CreateComments < ActiveRecord::Migration 3 | def change 4 | create_table :comments do |t| 5 | t.integer :user_id 6 | t.string :text 7 | t.integer :votes 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /example_rails_app/db/migrate/20140731144123_create_subscriptions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class CreateSubscriptions < ActiveRecord::Migration 3 | def change 4 | create_table :subscriptions do |t| 5 | t.string :type 6 | t.integer :user_id 7 | t.boolean :active 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /example_rails_app/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # frozen_string_literal: true 3 | # This file is auto-generated from the current state of the database. Instead 4 | # of editing this file, please use the migrations feature of Active Record to 5 | # incrementally modify your database, and then regenerate this schema definition. 6 | # 7 | # Note that this schema.rb definition is the authoritative source for your 8 | # database schema. If you need to create the application database on another 9 | # system, you should be using db:schema:load, not running all the migrations 10 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 11 | # you'll amass, the slower it'll run and the greater likelihood for issues). 12 | # 13 | # It's strongly recommended that you check this file into your version control system. 14 | 15 | ActiveRecord::Schema.define(version: 20_140_731_144_123) do 16 | create_table "comments", force: true do |t| 17 | t.integer "user_id" 18 | t.string "text" 19 | t.integer "votes" 20 | t.datetime "created_at" 21 | t.datetime "updated_at" 22 | end 23 | 24 | create_table "subscriptions", force: true do |t| 25 | t.string "kind" 26 | t.integer "user_id" 27 | t.boolean "active" 28 | t.datetime "created_at" 29 | t.datetime "updated_at" 30 | end 31 | 32 | create_table "users", force: true do |t| 33 | t.string "name" 34 | t.integer "age" 35 | t.boolean "admin" 36 | t.datetime "created_at" 37 | t.datetime "updated_at" 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /example_rails_app/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file should contain all the record creation needed to seed the database with its default values. 3 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 4 | # 5 | # Examples: 6 | # 7 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 8 | # Mayor.create(name: 'Emanuel', city: cities.first) 9 | -------------------------------------------------------------------------------- /example_rails_app/example_rails_app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example_rails_app/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/lib/assets/.keep -------------------------------------------------------------------------------- /example_rails_app/lib/subscribe_user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class SubscribeUser 3 | attr_accessor :user 4 | 5 | def initialize(user: user) 6 | @user = user 7 | end 8 | 9 | def with_yearly 10 | Subscription.create(user: user, kind: "yearly") 11 | end 12 | 13 | def with_monthly 14 | Subscription.create(user: user, kind: "monthly") 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /example_rails_app/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/lib/tasks/.keep -------------------------------------------------------------------------------- /example_rails_app/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/log/.keep -------------------------------------------------------------------------------- /example_rails_app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

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

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /example_rails_app/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

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

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /example_rails_app/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

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

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /example_rails_app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/public/favicon.ico -------------------------------------------------------------------------------- /example_rails_app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /example_rails_app/spec/lib/subscribe_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "lib/subscribe_user" 4 | require "spec/mocks/user_mock" 5 | require "spec/mocks/subscription_mock" 6 | 7 | RSpec.describe SubscribeUser, active_mocker: true do 8 | let(:user) { User.create } 9 | 10 | subject { described_class.new(user: user) } 11 | 12 | describe "with_yearly" do 13 | it do 14 | subject.with_yearly 15 | expect( 16 | Subscription.where(user: user, 17 | kind: "yearly").count, 18 | ).to eq 1 19 | end 20 | end 21 | 22 | describe "with_monthly" do 23 | it do 24 | subject.with_monthly 25 | expect(Subscription.where(user: user, kind: "monthly").count).to eq 1 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /example_rails_app/spec/mocks/comment_mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_mocker/mock" 3 | 4 | class CommentMock < ActiveMocker::Mock::Base 5 | created_with("2.0.0-alpha.0") 6 | # _modules_constants.erb 7 | 8 | # _class_methods.erb 9 | class << self 10 | def attributes 11 | @attributes ||= HashWithIndifferentAccess.new("id" => nil, "user_id" => nil, "text" => nil, "votes" => nil, "created_at" => nil, "updated_at" => nil).merge(super) 12 | end 13 | 14 | def types 15 | @types ||= ActiveMocker::HashProcess.new({ id: Fixnum, user_id: Fixnum, text: String, votes: Fixnum, created_at: DateTime, updated_at: DateTime }, method(:build_type)).merge(super) 16 | end 17 | 18 | def associations 19 | @associations ||= { user: nil }.merge(super) 20 | end 21 | 22 | def associations_by_class 23 | @associations_by_class ||= { User: { belongs_to: [:user] } }.merge(super) 24 | end 25 | 26 | def mocked_class 27 | "Comment" 28 | end 29 | 30 | private :mocked_class 31 | 32 | def attribute_names 33 | @attribute_names ||= %w(id user_id text votes created_at updated_at) | super 34 | end 35 | 36 | def primary_key 37 | "id" 38 | end 39 | 40 | def abstract_class? 41 | false 42 | end 43 | 44 | def table_name 45 | "comments" || super 46 | end 47 | end 48 | # _attributes.erb 49 | def id 50 | read_attribute(:id) 51 | end 52 | 53 | def id=(val) 54 | write_attribute(:id, val) 55 | end 56 | 57 | def user_id 58 | read_attribute(:user_id) 59 | end 60 | 61 | def user_id=(val) 62 | write_attribute(:user_id, val) 63 | end 64 | 65 | def text 66 | read_attribute(:text) 67 | end 68 | 69 | def text=(val) 70 | write_attribute(:text, val) 71 | end 72 | 73 | def votes 74 | read_attribute(:votes) 75 | end 76 | 77 | def votes=(val) 78 | write_attribute(:votes, val) 79 | end 80 | 81 | def created_at 82 | read_attribute(:created_at) 83 | end 84 | 85 | def created_at=(val) 86 | write_attribute(:created_at, val) 87 | end 88 | 89 | def updated_at 90 | read_attribute(:updated_at) 91 | end 92 | 93 | def updated_at=(val) 94 | write_attribute(:updated_at, val) 95 | end 96 | 97 | # _associations.erb 98 | 99 | # belongs_to 100 | def user 101 | read_association(:user) || write_association(:user, classes("User").try { |k| k.find_by(id: user_id) }) 102 | end 103 | 104 | def user=(val) 105 | write_association(:user, val) 106 | ActiveMocker::BelongsTo.new(val, child_self: self, foreign_key: :user_id).item 107 | end 108 | 109 | def build_user(attributes = {}, &block) 110 | association = classes("User").try(:new, attributes, &block) 111 | write_association(:user, association) unless association.nil? 112 | end 113 | 114 | def create_user(attributes = {}, &block) 115 | association = classes("User").try(:create, attributes, &block) 116 | write_association(:user, association) unless association.nil? 117 | end 118 | alias create_user! create_user 119 | 120 | # _scopes.erb 121 | module Scopes 122 | include ActiveMocker::Base::Scopes 123 | end 124 | 125 | extend Scopes 126 | 127 | class ScopeRelation < ActiveMocker::Association 128 | include CommentMock::Scopes 129 | end 130 | 131 | def self.__new_relation__(collection) 132 | CommentMock::ScopeRelation.new(collection) 133 | end 134 | 135 | private_class_method :__new_relation__ 136 | end 137 | -------------------------------------------------------------------------------- /example_rails_app/spec/mocks/subscription_mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_mocker/mock" 3 | 4 | class SubscriptionMock < ActiveMocker::Base 5 | created_with("2.0.0-alpha.0") 6 | # _modules_constants.erb 7 | 8 | # _class_methods.erb 9 | class << self 10 | def attributes 11 | @attributes ||= HashWithIndifferentAccess.new("id" => nil, "kind" => nil, "user_id" => nil, "active" => nil, "created_at" => nil, "updated_at" => nil).merge(super) 12 | end 13 | 14 | def types 15 | @types ||= ActiveMocker::HashProcess.new({ id: Fixnum, kind: String, user_id: Fixnum, active: Axiom::Types::Boolean, created_at: DateTime, updated_at: DateTime }, method(:build_type)).merge(super) 16 | end 17 | 18 | def associations 19 | @associations ||= { user: nil }.merge(super) 20 | end 21 | 22 | def associations_by_class 23 | @associations_by_class ||= { User: { belongs_to: [:user] } }.merge(super) 24 | end 25 | 26 | def mocked_class 27 | "Subscription" 28 | end 29 | 30 | private :mocked_class 31 | 32 | def attribute_names 33 | @attribute_names ||= %w(id kind user_id active created_at updated_at) | super 34 | end 35 | 36 | def primary_key 37 | "id" 38 | end 39 | 40 | def abstract_class? 41 | false 42 | end 43 | 44 | def table_name 45 | "subscriptions" || super 46 | end 47 | end 48 | # _attributes.erb 49 | def id 50 | read_attribute(:id) 51 | end 52 | 53 | def id=(val) 54 | write_attribute(:id, val) 55 | end 56 | 57 | def kind 58 | read_attribute(:kind) 59 | end 60 | 61 | def kind=(val) 62 | write_attribute(:kind, val) 63 | end 64 | 65 | def user_id 66 | read_attribute(:user_id) 67 | end 68 | 69 | def user_id=(val) 70 | write_attribute(:user_id, val) 71 | end 72 | 73 | def active 74 | read_attribute(:active) 75 | end 76 | 77 | def active=(val) 78 | write_attribute(:active, val) 79 | end 80 | 81 | def created_at 82 | read_attribute(:created_at) 83 | end 84 | 85 | def created_at=(val) 86 | write_attribute(:created_at, val) 87 | end 88 | 89 | def updated_at 90 | read_attribute(:updated_at) 91 | end 92 | 93 | def updated_at=(val) 94 | write_attribute(:updated_at, val) 95 | end 96 | 97 | # _associations.erb 98 | 99 | # belongs_to 100 | def user 101 | read_association(:user) || write_association(:user, classes("User").try { |k| k.find_by(id: user_id) }) 102 | end 103 | 104 | def user=(val) 105 | write_association(:user, val) 106 | ActiveMocker::BelongsTo.new(val, child_self: self, foreign_key: :user_id).item 107 | end 108 | 109 | def build_user(attributes = {}, &block) 110 | association = classes("User").try(:new, attributes, &block) 111 | write_association(:user, association) unless association.nil? 112 | end 113 | 114 | def create_user(attributes = {}, &block) 115 | association = classes("User").try(:create, attributes, &block) 116 | write_association(:user, association) unless association.nil? 117 | end 118 | alias create_user! create_user 119 | 120 | # _scopes.erb 121 | module Scopes 122 | include ActiveMocker::Base::Scopes 123 | end 124 | 125 | extend Scopes 126 | 127 | class ScopeRelation < ActiveMocker::Association 128 | include SubscriptionMock::Scopes 129 | end 130 | 131 | def self.__new_relation__(collection) 132 | SubscriptionMock::ScopeRelation.new(collection) 133 | end 134 | 135 | private_class_method :__new_relation__ 136 | end 137 | -------------------------------------------------------------------------------- /example_rails_app/spec/mocks/user_mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_mocker/mock" 3 | 4 | class UserMock < ActiveMocker::Base 5 | created_with("2.0.0-alpha.0") 6 | # _modules_constants.erb 7 | 8 | # _class_methods.erb 9 | class << self 10 | def attributes 11 | @attributes ||= HashWithIndifferentAccess.new("id" => nil, "name" => nil, "age" => nil, "admin" => nil, "created_at" => nil, "updated_at" => nil).merge(super) 12 | end 13 | 14 | def types 15 | @types ||= ActiveMocker::HashProcess.new({ id: Fixnum, name: String, age: Fixnum, admin: Axiom::Types::Boolean, created_at: DateTime, updated_at: DateTime }, method(:build_type)).merge(super) 16 | end 17 | 18 | def associations 19 | @associations ||= { comments: nil, subscriptions: nil }.merge(super) 20 | end 21 | 22 | def associations_by_class 23 | @associations_by_class ||= { Comment: { has_many: [:comments] }, Subscription: { has_many: [:subscriptions] } }.merge(super) 24 | end 25 | 26 | def mocked_class 27 | "User" 28 | end 29 | 30 | private :mocked_class 31 | 32 | def attribute_names 33 | @attribute_names ||= %w(id name age admin created_at updated_at) | super 34 | end 35 | 36 | def primary_key 37 | "id" 38 | end 39 | 40 | def abstract_class? 41 | false 42 | end 43 | 44 | def table_name 45 | "users" || super 46 | end 47 | end 48 | # _attributes.erb 49 | def id 50 | read_attribute(:id) 51 | end 52 | 53 | def id=(val) 54 | write_attribute(:id, val) 55 | end 56 | 57 | def name 58 | read_attribute(:name) 59 | end 60 | 61 | def name=(val) 62 | write_attribute(:name, val) 63 | end 64 | 65 | def age 66 | read_attribute(:age) 67 | end 68 | 69 | def age=(val) 70 | write_attribute(:age, val) 71 | end 72 | 73 | def admin 74 | read_attribute(:admin) 75 | end 76 | 77 | def admin=(val) 78 | write_attribute(:admin, val) 79 | end 80 | 81 | def created_at 82 | read_attribute(:created_at) 83 | end 84 | 85 | def created_at=(val) 86 | write_attribute(:created_at, val) 87 | end 88 | 89 | def updated_at 90 | read_attribute(:updated_at) 91 | end 92 | 93 | def updated_at=(val) 94 | write_attribute(:updated_at, val) 95 | end 96 | 97 | # _associations.erb 98 | 99 | # has_many 100 | def comments 101 | read_association(:comments, -> { ActiveMocker::HasMany.new([], foreign_key: "user_id", foreign_id: id, relation_class: classes("Comment"), source: "") }) 102 | end 103 | 104 | def comments=(val) 105 | write_association(:comments, ActiveMocker::HasMany.new(val, foreign_key: "user_id", foreign_id: id, relation_class: classes("Comment"), source: "")) 106 | end 107 | 108 | def subscriptions 109 | read_association(:subscriptions, -> { ActiveMocker::HasMany.new([], foreign_key: "user_id", foreign_id: id, relation_class: classes("Subscription"), source: "") }) 110 | end 111 | 112 | def subscriptions=(val) 113 | write_association(:subscriptions, ActiveMocker::HasMany.new(val, foreign_key: "user_id", foreign_id: id, relation_class: classes("Subscription"), source: "")) 114 | end 115 | 116 | # _scopes.erb 117 | module Scopes 118 | include ActiveMocker::Base::Scopes 119 | end 120 | 121 | extend Scopes 122 | 123 | class ScopeRelation < ActiveMocker::Association 124 | include UserMock::Scopes 125 | end 126 | 127 | def self.__new_relation__(collection) 128 | UserMock::ScopeRelation.new(collection) 129 | end 130 | 131 | private_class_method :__new_relation__ 132 | end 133 | -------------------------------------------------------------------------------- /example_rails_app/spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | ENV["RAILS_ENV"] ||= "test" 3 | require "spec_helper" 4 | require File.expand_path("../../config/environment", __FILE__) 5 | require "rspec/rails" 6 | 7 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 8 | 9 | ActiveRecord::Migration.maintain_test_schema! 10 | 11 | RSpec.configure do |config| 12 | config.use_transactional_fixtures = true 13 | 14 | config.infer_spec_type_from_file_location! 15 | end 16 | -------------------------------------------------------------------------------- /example_rails_app/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | $VERBOSE = nil # This removes ruby warnings 3 | require "active_mocker/rspec_helper" 4 | $LOAD_PATH.unshift File.join(File.expand_path("../../", __FILE__)) # add root of app to path 5 | RSpec.configure do |config| 6 | config.order = "random" 7 | config.mock_framework = :rspec 8 | config.disable_monkey_patching! 9 | config.mock_with :rspec do |mocks| 10 | mocks.syntax = :expect 11 | mocks.verify_doubled_constant_names = true 12 | mocks.verify_partial_doubles = true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /example_rails_app/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /example_rails_app/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/example_rails_app/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /lib/active_mocker.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # _ _ __ __ _ 3 | # /\ | | (_) | \/ | | | 4 | # / \ ___| |_ ___ _____| \ / | ___ ___| | _____ _ __ 5 | # / /\ \ / __| __| \ \ / / _ \ |\/| |/ _ \ / __| |/ / _ \ '__| 6 | # / ____ \ (__| |_| |\ V / __/ | | | (_) | (__| < __/ | 7 | # /_/ \_\___|\__|_| \_/ \___|_| |_|\___/ \___|_|\_\___|_| 8 | # 9 | # By Dustin Zeisler 10 | 11 | require "rubygems" 12 | require "active_mocker/version" 13 | require "active_mocker/railtie" if defined?(Rails) 14 | require "forwardable" 15 | require "active_support/all" 16 | require "active_mocker/public_methods" 17 | require "active_mocker/config" 18 | require "reverse_parameters" 19 | require "active_record_schema_scrapper" 20 | require "dissociated_introspection" 21 | require "active_mocker/file_path_to_ruby_class" 22 | require "active_mocker/hash_new_style" 23 | require "active_mocker/null_progress" 24 | require "active_mocker/progress" 25 | require "active_mocker/parent_class" 26 | require "active_mocker/template_creator" 27 | require "active_mocker/mock_creator" 28 | require "active_mocker/mock_creator/associations" 29 | require "active_mocker/mock_creator/attributes" 30 | require "active_mocker/mock_creator/class_methods" 31 | require "active_mocker/mock_creator/defined_methods" 32 | require "active_mocker/mock_creator/modules_constants" 33 | require "active_mocker/mock_creator/recreate_class_method_calls" 34 | require "active_mocker/mock_creator/scopes" 35 | require "active_mocker/mock_creator/mock_build_version" 36 | require "active_mocker/error_object" 37 | require "active_mocker/display_errors" 38 | require "active_mocker/generate" 39 | require "active_mocker/attribute_types/register" 40 | require "active_mocker/attribute_types/enum" 41 | require "active_mocker/attribute" 42 | require "active_mocker/late_inclusion" 43 | -------------------------------------------------------------------------------- /lib/active_mocker/attribute.rb: -------------------------------------------------------------------------------- 1 | ActiveRecordSchemaScrapper::Attribute.attribute :attribute_writer, String 2 | ActiveRecordSchemaScrapper::Attribute.attribute :attribute_reader, String 3 | -------------------------------------------------------------------------------- /lib/active_mocker/attribute_types/enum.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "virtus" 3 | 4 | module ActiveMocker 5 | module AttributeTypes 6 | class Enum < Virtus::Attribute 7 | class << self 8 | def build(db_value_type:, table_name:, attribute:, enums:, ignore_value: false) 9 | klass = Class.new(ActiveMocker::AttributeTypes::Enum) 10 | klass.table_name = table_name.to_sym 11 | klass.attribute = attribute.to_sym 12 | klass.ignore_value = ignore_value 13 | enums = if enums.is_a?(Array) 14 | enums.each_with_object({}).with_index { |(k, h), i| h[k] = i } 15 | else 16 | enums 17 | end 18 | klass.key_type = String 19 | klass.db_value_type = db_value_type 20 | klass.enums = Hash[enums.map do |k, v| 21 | [Virtus::Attribute.build(klass.key_type).coerce(k), 22 | Virtus::Attribute.build(klass.db_value_type).coerce(v)] 23 | end] 24 | klass 25 | end 26 | 27 | def to_s 28 | "ActiveMocker::AttributeTypes::Enum.build(ignore_value: #{ignore_value}, db_value_type: #{db_value_type}, table_name: :#{table_name}, attribute: :#{attribute}, enums: #{enums.inspect})" 29 | end 30 | 31 | attr_accessor :enums, :table_name, :attribute, :db_value_type, :key_type, :ignore_value 32 | end 33 | 34 | def coerce(key) 35 | return if key.nil? 36 | coerced_key = key_type.coerce(key) 37 | if key && self.class.enums.key?(coerced_key) 38 | if self.class.ignore_value 39 | coerced_key 40 | else 41 | get_value(key) 42 | end 43 | else 44 | raise ArgumentError, "'#{coerced_key}' is not a valid #{self.class.attribute}" 45 | end 46 | end 47 | 48 | def get_key(value) 49 | self.class.enums.invert[db_value_type.coerce(value)] 50 | end 51 | 52 | def get_value(key) 53 | self.class.enums[key_type.coerce(key)] 54 | end 55 | 56 | def key_type 57 | Virtus::Attribute.build(self.class.key_type) 58 | end 59 | 60 | def db_value_type 61 | Virtus::Attribute.build(self.class.db_value_type) 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/active_mocker/attribute_types/register.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | ActiveRecordSchemaScrapper::Attributes.register_type(name: :enum, klass: String) 3 | -------------------------------------------------------------------------------- /lib/active_mocker/config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Config 4 | class << self 5 | attr_accessor :model_dir, 6 | :mock_dir, 7 | :single_model_path, 8 | :progress_bar, 9 | :error_verbosity, 10 | :disable_modules_and_constants, 11 | :mock_append_name 12 | 13 | attr_writer :model_base_classes 14 | 15 | # @see ActiveMocker#configure 16 | def set 17 | load_defaults 18 | yield self 19 | end 20 | 21 | def load_defaults 22 | @error_verbosity = 1 23 | @progress_bar = true 24 | @disable_modules_and_constants = false 25 | @model_dir = nil unless @model_dir 26 | @mock_dir = nil unless @mock_dir 27 | @mock_append_name = "Mock" 28 | rails_defaults if Object.const_defined?("Rails") 29 | end 30 | 31 | def reset_all 32 | [:model_dir, 33 | :mock_dir, 34 | :log_location, 35 | :single_model_path, 36 | :progress_bar, 37 | :error_verbosity, 38 | :mock_append_name, 39 | ].each { |ivar| instance_variable_set("@#{ivar}", nil) } 40 | end 41 | 42 | def rails_defaults 43 | @model_dir = File.join(Rails.root, "app/models") unless @model_dir 44 | @mock_dir = File.join(Rails.root, "spec/mocks") unless @mock_dir 45 | end 46 | 47 | def progress_class 48 | @progress_bar ? Progress : NullProgress 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/active_mocker/display_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "colorize" 3 | module ActiveMocker 4 | class DisplayErrors 5 | attr_reader :errors, :model_count, :out 6 | attr_accessor :success_count, :failed_models 7 | 8 | def initialize(model_count, out: STDERR) 9 | @errors = [] 10 | @success_count = 0 11 | @model_count = model_count 12 | @failed_models = [] 13 | @out = out 14 | end 15 | 16 | def add(errors) 17 | @errors.concat([*errors]) 18 | end 19 | 20 | def wrap_errors(errors, model_name, type: nil) 21 | add errors.map { |e| ErrorObject.build_from(object: e, class_name: model_name, type: type ? type : e.try(:type)) } 22 | end 23 | 24 | def wrap_an_exception(e, model_name) 25 | add ErrorObject.build_from(exception: e, class_name: model_name) 26 | end 27 | 28 | def uniq_errors 29 | @uniq_errors ||= errors.flatten.compact.uniq.sort_by(&:class_name) 30 | end 31 | 32 | def any_errors? 33 | uniq_errors.count > 0 34 | end 35 | 36 | def display_errors 37 | uniq_errors.each do |e| 38 | next unless ENV["DEBUG"] || !(e.level == :debug) 39 | 40 | display_verbosity_three(e) || display_verbosity_two(e) 41 | end 42 | 43 | display_verbosity_one 44 | end 45 | 46 | def error_summary 47 | display "errors: #{error_count}, warn: #{warn}, info: #{info}" 48 | display "Failed models: #{failed_models.join(", ")}" if failed_models.count > 0 49 | end 50 | 51 | def number_models_mocked 52 | if success_count < model_count || any_errors? 53 | display "Mocked #{success_count} ActiveRecord #{plural("Model", success_count)} out of #{model_count} #{plural("file", model_count)}." 54 | end 55 | end 56 | 57 | private 58 | 59 | def plural(string, count, plural="s") 60 | count > 1 || count.zero? ? "#{string}#{plural}" : string 61 | end 62 | 63 | def display(msg) 64 | out.puts(msg) 65 | end 66 | 67 | def display_verbosity_three(error) 68 | return unless ActiveMocker::Config.error_verbosity == 3 69 | 70 | display_error_header(error) 71 | display error.level 72 | 73 | display_original_error(error) 74 | end 75 | 76 | def display_original_error(e) 77 | original = e.original_error 78 | return unless original 79 | 80 | display original.message.colorize(e.level_color) 81 | display original.backtrace 82 | display original.class.name.colorize(e.level_color) 83 | end 84 | 85 | def display_verbosity_two(e) 86 | return unless ActiveMocker::Config.error_verbosity == 2 87 | 88 | display_error_header(e) 89 | end 90 | 91 | def display_error_header(e) 92 | display "#{e.class_name} has the following errors:" 93 | display e.message.colorize(e.level_color) 94 | end 95 | 96 | def display_verbosity_one 97 | return unless ActiveMocker::Config.error_verbosity > 0 98 | 99 | error_summary if any_errors? 100 | 101 | number_models_mocked 102 | 103 | return unless any_errors? 104 | display "To see more/less detail set ERROR_VERBOSITY = 0, 1, 2, 3" 105 | end 106 | 107 | def error_count 108 | errors_for(:red) 109 | end 110 | 111 | def warn 112 | errors_for(:yellow) 113 | end 114 | 115 | def info 116 | errors_for(:default) 117 | end 118 | 119 | def errors_for(level) 120 | uniq_errors.count { |e| [level].include? e.level_color } 121 | end 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /lib/active_mocker/error_object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class ErrorObject 4 | attr_reader :message, :level, :original_error, :type, :class_name 5 | 6 | def initialize(level: :warn, message:, class_name:, type:, original_error: nil) 7 | @level = level 8 | @message = message 9 | @class_name = class_name 10 | @type = type 11 | @original_error = original_error 12 | end 13 | 14 | def self.build_from(object: nil, exception: nil, class_name: nil, type: nil) 15 | if object 16 | args = [:message, :original_error, :level, :type, :class_name].each_with_object({}) do |meth, hash| 17 | hash[meth] = object.public_send(meth) if object.respond_to? meth 18 | end 19 | args[:type] = type unless type.nil? 20 | args[:class_name] = class_name unless class_name.nil? 21 | return new(args) 22 | elsif exception && class_name 23 | return new(message: exception.message, 24 | class_name: class_name, 25 | original_error: exception, 26 | type: type ? type : :standard_error) 27 | end 28 | raise ArgumentError 29 | end 30 | 31 | def original_error? 32 | !original_error.nil? 33 | end 34 | 35 | def level_color 36 | case level 37 | when :standard_error, :fatal, :error 38 | :red 39 | when :warn 40 | :yellow 41 | when :info 42 | :default 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/active_mocker/file_path_to_ruby_class.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class FilePathToRubyClass 4 | attr_reader :class_path, :base_path 5 | 6 | def initialize(base_path:, class_path:) 7 | @base_path = base_path 8 | @class_path = class_path 9 | end 10 | 11 | def to_s 12 | File.basename(class_path.gsub(base_path + "/", "").split("/").map(&:camelize).join("::"), ".rb") 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/active_mocker/file_writer.rb: -------------------------------------------------------------------------------- 1 | module ActiveMocker 2 | class FileWriter 3 | include Virtus.model 4 | delegate :name, to: :model, prefix: true 5 | 6 | attribute :model, Object 7 | attribute :file, String 8 | attribute :display_errors 9 | attribute :config 10 | attribute :model_names, Array 11 | 12 | def write! 13 | assure_dir_path_exists! 14 | 15 | safe_write { |f| process!(f) } 16 | end 17 | 18 | private 19 | 20 | def process!(file_out) 21 | result = create_mock(file_out, model) 22 | status = collect_errors(result.errors) 23 | 24 | ok = result.completed? && status.successful? 25 | return unless ok 26 | 27 | display_errors.success_count += 1 28 | end 29 | 30 | def safe_write 31 | File.open(mock_file_path, "w") do |file_out| 32 | begin 33 | yield file_out 34 | rescue StandardError => e 35 | rescue_clean_up(e, file_out) 36 | end 37 | end 38 | end 39 | 40 | def rescue_clean_up(e, file_out) 41 | display_errors.failed_models << model_name 42 | file_out.close unless file_out.closed? 43 | File.delete(file_out.path) if File.exist?(file_out.path) 44 | display_errors.wrap_an_exception(e, model_name) 45 | end 46 | 47 | def scrapper 48 | @scrapper ||= ActiveRecordSchemaScrapper.new(model: model) 49 | end 50 | 51 | def mock_file_path 52 | File.join(Config.mock_dir, mock_file_name) 53 | end 54 | 55 | def mock_file_name 56 | "#{model_name.underscore}_#{config.mock_append_name.underscore}.rb" 57 | end 58 | 59 | def assure_dir_path_exists! 60 | unless File.exist?(File.dirname(mock_file_path)) 61 | FileUtils.mkdir_p(File.dirname(mock_file_path)) 62 | end 63 | end 64 | 65 | def create_mock(file_out, model) 66 | MockCreator.new(file: File.open(file), 67 | file_out: file_out, 68 | schema_scrapper: scrapper, 69 | klasses_to_be_mocked: model_names, 70 | enabled_partials: enabled_partials, 71 | mock_append_name: config.mock_append_name, 72 | active_record_model: model).create 73 | end 74 | 75 | OtherErrors = Struct.new(:successful?) 76 | 77 | def collect_errors(create_mock_errors) 78 | add_errors! 79 | 80 | if create_mock_errors.present? || schema.attribute_errors? 81 | display_errors.failed_models << model_name 82 | File.delete(mock_file_path) if File.exist?(mock_file_path) 83 | display_errors.add(create_mock_errors) 84 | OtherErrors.new(false) 85 | else 86 | OtherErrors.new(true) 87 | end 88 | end 89 | 90 | def add_errors! 91 | add_error(schema.association_errors, :associations) 92 | add_error(schema.attribute_errors, :attributes) 93 | end 94 | 95 | def add_error(error, type) 96 | display_errors.wrap_errors(error, model_name, type: type) 97 | end 98 | 99 | def enabled_partials 100 | if config.disable_modules_and_constants 101 | MockCreator::ENABLED_PARTIALS_DEFAULT - [*:modules_constants] 102 | else 103 | MockCreator::ENABLED_PARTIALS_DEFAULT 104 | end 105 | end 106 | 107 | def schema 108 | @schema ||= Schema.new(ActiveRecordSchemaScrapper.new(model: model)) 109 | end 110 | 111 | class Schema < SimpleDelegator 112 | def attribute_errors? 113 | attribute_errors.any? { |e| e.level == :error } 114 | end 115 | 116 | def association_errors 117 | associations.errors 118 | end 119 | 120 | def attribute_errors 121 | attributes.errors 122 | end 123 | end 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /lib/active_mocker/generate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative "file_writer" 3 | 4 | module ActiveMocker 5 | class Generate 6 | def initialize 7 | check_directory!(:mock_dir) 8 | create_mock_dir 9 | check_directory!(:model_dir) 10 | raise_missing_arg(:model_dir) unless Dir.exist?(config.model_dir) 11 | 12 | @display_errors = DisplayErrors.new(models_paths.count) 13 | end 14 | 15 | # @return self 16 | def call 17 | clean_up 18 | progress_init 19 | 20 | active_record_models_with_files.each do |model, file| 21 | write_file(model, file) 22 | 23 | progress.increment 24 | end 25 | 26 | display_errors.display_errors 27 | self 28 | end 29 | 30 | def active_record_models 31 | @active_record_models ||= active_record_models_with_files.map(&:first) 32 | end 33 | 34 | private 35 | 36 | attr_reader :display_errors, :progress 37 | 38 | def check_directory!(type) 39 | value = config.send(type) 40 | 41 | if value.nil? || value.empty? 42 | raise_missing_arg(type) 43 | end 44 | end 45 | 46 | def raise_missing_arg(type) 47 | raise ArgumentError, "#{type} is missing a valued value!" 48 | end 49 | 50 | def write_file(model, file) 51 | writer = FileWriter.new( 52 | model: model, 53 | file: file, 54 | display_errors: display_errors, 55 | config: config, 56 | model_names: model_names) 57 | 58 | writer.write! 59 | end 60 | 61 | def progress_init 62 | @progress = config.progress_class.create(active_record_models.count) 63 | end 64 | 65 | def model_names 66 | @model_names ||= active_record_models.map(&:name) 67 | end 68 | 69 | def active_record_models_with_files 70 | @active_record_models_with_files ||= models_paths.map do |file| 71 | model = constant_from(model_name_from(file)) 72 | [model, file] if model 73 | end.compact 74 | end 75 | 76 | def models_paths 77 | @models_paths ||= Dir.glob(config.single_model_path || File.join(config.model_dir, "**/*.rb")) 78 | end 79 | 80 | def constant_from(model_name) 81 | constant = model_name.constantize 82 | return unless constant.ancestors.include?(ActiveRecord::Base) 83 | constant 84 | rescue NameError, LoadError => e 85 | display_errors.wrap_an_exception(e, model_name) 86 | nil 87 | end 88 | 89 | def model_name_from(file) 90 | FilePathToRubyClass.new( 91 | base_path: config.model_dir, 92 | class_path: file 93 | ).to_s 94 | end 95 | 96 | def config 97 | ActiveMocker::Config 98 | end 99 | 100 | def create_mock_dir 101 | FileUtils.mkdir_p(config.mock_dir) unless Dir.exist?(config.mock_dir) 102 | end 103 | 104 | def clean_up 105 | delete_mocks unless config.single_model_path 106 | end 107 | 108 | def delete_mocks 109 | FileUtils.rm Dir.glob(File.join(config.mock_dir, "/**/*_#{config.mock_append_name.underscore}.rb")) 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /lib/active_mocker/hash_new_style.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class HashNewStyle < Hash 4 | def inspect 5 | "{ " + map { |name, type| "#{name}: #{type}" }.join(", ") + " }" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_mocker/inspectable/bigdecimal" 3 | require "active_mocker/inspectable/date" 4 | require "active_mocker/inspectable/dir" 5 | require "active_mocker/inspectable/file" 6 | require "active_mocker/inspectable/pathname" 7 | require "active_mocker/inspectable/struct" 8 | require "active_mocker/inspectable/time" 9 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/bigdecimal.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine BigDecimal do 5 | def inspect 6 | "BigDecimal(\"%s\")" % to_s('F') 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/date.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Date do 5 | def inspect 6 | "Date.new(%s, %s, %s)" % [year, month, day] 7 | end 8 | end 9 | 10 | refine DateTime do 11 | def inspect 12 | strftime("DateTime.new(%Y, %-m, %-d, %-H, %-M, %-S, \"%:z\")") 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/dir.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Dir do 5 | def inspect 6 | "Dir.new(#{path.inspect})" 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/file.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Dir do 5 | def File 6 | "File.new(#{path.inspect})" 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/pathname.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Pathname do 5 | def inspect 6 | "Pathname(#{to_s.inspect})" 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/struct.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Struct do 5 | def inspect 6 | "%s.new(%s)" % [self.class.name, values.map(&:inspectable).join(", ")] 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/inspectable/time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Inspectable 4 | refine Time do 5 | def inspect 6 | strftime("Time.new(%Y, %-m, %-d, %-H, %-M, %-S, \"%:z\")") 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/late_inclusion.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveMocker 4 | module LateInclusion 5 | module Extension 6 | def prepended(const) 7 | if const.respond_to?(:__extended_onto__) 8 | const.__extended_onto__.each do |ex| 9 | ex.extend self 10 | end 11 | end 12 | 13 | if const.respond_to?(:__included_onto__) 14 | const.__included_onto__.each do |ex| 15 | ex.prepend self 16 | end 17 | end 18 | end 19 | end 20 | 21 | def extended(const) 22 | __extended_onto__ << const 23 | end 24 | 25 | def __extended_onto__ 26 | @__extended_onto__ ||= [] 27 | end 28 | 29 | def included(const) 30 | __included_onto__ << const 31 | end 32 | 33 | def __included_onto__ 34 | @__included_onto__ ||= [] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/active_mocker/loaded_mocks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "forwardable" 4 | require_relative "loaded_mocks/features" 5 | 6 | module ActiveMocker 7 | class LoadedMocks 8 | class << self 9 | extend Forwardable 10 | def_delegators :mocks, :find, :delete_all 11 | 12 | # Returns an Enumerable of all currently loaded mocks. 13 | # 14 | # ActiveMocker::LoadedMocks.mocks 15 | # => PersonMock}> 16 | # @return ActiveMocker::LoadedMocks::Collection 17 | def mocks 18 | Collection.new(mocks_store.values.each_with_object({}) do |mock_constant, hash| 19 | hash[mock_constant.send(:mocked_class)] = mock_constant 20 | end) 21 | end 22 | 23 | # @deprecated Use {#mocks} instead of this method. 24 | alias class_name_to_mock mocks 25 | 26 | # @deprecated Use {#mocks} instead of this method. 27 | alias all mocks 28 | 29 | # @deprecated Use {#delete_all} instead of this method. 30 | alias clear_all delete_all 31 | 32 | def features 33 | @features ||= Features.instance 34 | end 35 | 36 | class Collection 37 | include Enumerable 38 | 39 | # @option opts [Hash] hash 40 | def initialize(hash = {}) 41 | @hash = Hash[hash] 42 | end 43 | 44 | extend Forwardable 45 | def_delegators :hash, :[]=, :[], :each, :to_hash, :to_h 46 | 47 | # Calls {#delete_all} for all mocks globally, which removes all records that were saved or created. 48 | # @return [NilClass] 49 | def delete_all 50 | mocks.each(&__method__) 51 | end 52 | 53 | # @param [Array] args an array of ActiveRecord Model Names as Strings or Symbols 54 | # or of mock object. 55 | # @return [ActiveMocker::LoadedMocks::Collection] returns ActiveMock equivalent class. 56 | def slice(*args) 57 | self.class.new(select { |k, v| get_item(args, k, v) }) 58 | end 59 | 60 | # Input ActiveRecord Model Name as String or Symbol and it returns everything but that ActiveMock equivalent class. 61 | # except('User') => [AccountMock, OtherMock] 62 | # @param [Array] args 63 | # @return ActiveMocker::LoadedMocks::Collection 64 | def except(*args) 65 | self.class.new(reject { |k, v| get_item(args, k, v) }) 66 | end 67 | 68 | # Input ActiveRecord Model Name as String or Symbol returns ActiveMock equivalent class. 69 | # find('User') => UserMock 70 | # @param [Symbol, String, ActiveMocker::Mock] item 71 | # @return ActiveMocker::Mock 72 | def find(item) 73 | slice(item).mocks.first 74 | end 75 | 76 | # @return [Array] 77 | def mocks 78 | hash.values 79 | end 80 | alias values mocks 81 | 82 | private 83 | 84 | attr_reader :hash 85 | 86 | def get_item(args, k, v) 87 | args.map do |e| 88 | if [:to_str, :to_sym].any? { |i| e.respond_to? i } 89 | e.to_s == k 90 | else 91 | e == v 92 | end 93 | end.any? { |a| a } 94 | end 95 | end 96 | 97 | private 98 | 99 | def mocks_store 100 | @mocks ||= {} 101 | end 102 | 103 | def add(mocks_to_add) 104 | mocks_store.merge!(mocks_to_add.name => mocks_to_add) 105 | end 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/active_mocker/loaded_mocks/features.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "singleton" 3 | require "active_mocker/mock/exceptions" 4 | 5 | module ActiveMocker 6 | class LoadedMocks 7 | class Features 8 | include Singleton 9 | STUB_ACTIVE_RECORD_EXCEPTIONS = { 10 | "ActiveRecord::RecordNotFound" => ActiveMocker::RecordNotFound, 11 | "ActiveRecord::RecordNotUnique" => ActiveMocker::RecordNotUnique, 12 | "ActiveRecord::UnknownAttributeError" => ActiveMocker::UnknownAttributeError, 13 | } 14 | DEFAULTS = { 15 | timestamps: false, 16 | delete_all_before_example: false, 17 | stub_active_record_exceptions: STUB_ACTIVE_RECORD_EXCEPTIONS, 18 | }.freeze 19 | 20 | def initialize 21 | reset 22 | end 23 | 24 | def each(&block) 25 | @features.each(&block) 26 | end 27 | 28 | def enable(feature) 29 | update(feature, true) 30 | end 31 | 32 | def disable(feature) 33 | update(feature, false) 34 | end 35 | 36 | def [](feature) 37 | @features[feature] 38 | end 39 | 40 | def reset 41 | @features = DEFAULTS.dup 42 | end 43 | 44 | def to_h 45 | @features 46 | end 47 | 48 | private 49 | 50 | def update(feature, value) 51 | if @features.key?(feature) 52 | @features[feature] = value 53 | else 54 | raise KeyError, "#{feature} is not an available feature." 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/active_mocker/mock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_support/deprecation" 3 | require "active_support/dependencies/autoload" 4 | require "active_support/hash_with_indifferent_access" 5 | require "active_support/core_ext/module/delegation" 6 | require "active_support/inflector" 7 | require "active_support/core_ext" 8 | require "virtus" 9 | 10 | require "active_mocker/version" 11 | require "active_mocker/loaded_mocks" 12 | require "active_mocker/mock/hash_process" 13 | require "active_mocker/mock/collection" 14 | require "active_mocker/mock/queries" 15 | require "active_mocker/mock/mockable_method" 16 | require "active_mocker/mock/relation" 17 | require "active_mocker/mock/mock_relation" 18 | require "active_mocker/mock/association" 19 | require "active_mocker/mock/has_many" 20 | require "active_mocker/mock/single_relation" 21 | require "active_mocker/mock/has_one" 22 | require "active_mocker/mock/has_and_belongs_to_many" 23 | require "active_mocker/mock/belongs_to" 24 | require "active_mocker/mock/exceptions" 25 | require "active_mocker/mock/template_methods" 26 | require "active_mocker/mock/do_nothing_active_record_methods" 27 | require "active_mocker/mock/records" 28 | require "active_mocker/mock/object_inspect" 29 | require "active_mocker/mock/alias_attribute" 30 | require "active_mocker/mock/unrepresentable_const_value" 31 | require "active_mocker/attribute_types/enum" 32 | require "active_mocker/mock/base" 33 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/alias_attribute.rb: -------------------------------------------------------------------------------- 1 | module ActiveMocker 2 | module AliasAttribute 3 | # Is +new_name+ an alias? 4 | def attribute_alias?(new_name) 5 | attribute_aliases.key? new_name.to_s 6 | end 7 | 8 | # Returns the original name for the alias +name+ 9 | def attribute_alias(name) 10 | attribute_aliases[name.to_s] 11 | end 12 | 13 | private 14 | 15 | def attribute_aliases 16 | @attribute_aliases ||= {} 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/association.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Association < Relation 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/belongs_to.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class BelongsTo < SingleRelation 4 | attr_reader :item 5 | 6 | def initialize(item, child_self:, foreign_key:) 7 | save_item(item, child_self) 8 | assign_foreign_key(child_self, foreign_key, item.try(:id)) 9 | super 10 | end 11 | 12 | private 13 | 14 | def assign_foreign_key(child_self, foreign_key, foreign_id) 15 | child_self.send(:write_attribute, foreign_key, foreign_id) 16 | end 17 | 18 | def save_item(item, child_self) 19 | return if item.nil? 20 | item.try(:save) if child_self.persisted? 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/collection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "forwardable" 3 | 4 | module ActiveMocker 5 | class Collection 6 | include Enumerable 7 | extend ::Forwardable 8 | def_delegators :@collection, :[], :take, :push, :clear, :first, :last, :concat, :replace, :uniq, :count, :size, :length, :empty?, :any?, :many?, :include?, :delete 9 | alias distinct uniq 10 | 11 | def initialize(collection = []) 12 | @collection = collection 13 | end 14 | 15 | def <<(*records) 16 | collection.concat(records.flatten) 17 | end 18 | 19 | def each 20 | collection.each do |item| 21 | yield(item) 22 | end 23 | end 24 | 25 | def to_a 26 | @collection 27 | end 28 | 29 | def to_ary 30 | to_a 31 | end 32 | 33 | def hash 34 | @collection.hash 35 | end 36 | 37 | def ==(val) 38 | @collection == val 39 | end 40 | 41 | def blank? 42 | to_a.blank? 43 | end 44 | 45 | protected 46 | 47 | attr_accessor :collection 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/compatibility/base/ar51.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: tru 2 | module ActiveMocker 3 | class Base 4 | module AR51 5 | def delete_all 6 | super 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/compatibility/queries/ar52.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveMocker 4 | module Queries 5 | module AR52 6 | extend LateInclusion::Extension 7 | 8 | private 9 | 10 | def check_for_limit_scope! 11 | # noop 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/do_nothing_active_record_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module DoNothingActiveRecordMethods 4 | def self.included(base) 5 | base.extend(ClassMethods) 6 | end 7 | 8 | module ClassMethods 9 | def transaction(*) 10 | yield 11 | rescue LocalJumpError => err 12 | raise err 13 | rescue StandardError => e 14 | raise e 15 | end 16 | 17 | def column_names 18 | attribute_names 19 | end 20 | end 21 | 22 | def readonly? 23 | false 24 | end 25 | 26 | def errors 27 | obj = Object.new 28 | 29 | def obj.[](_key) 30 | [] 31 | end 32 | 33 | def obj.full_messages 34 | [] 35 | end 36 | 37 | obj 38 | end 39 | 40 | def valid? 41 | true 42 | end 43 | 44 | def marked_for_destruction? 45 | false 46 | end 47 | 48 | def destroyed? 49 | false 50 | end 51 | 52 | def reload 53 | self 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/exceptions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class BaseError < StandardError 4 | end 5 | class RecordNotFound < BaseError 6 | end 7 | class RecordNotUnique < BaseError 8 | end 9 | 10 | module Mock 11 | # @deprecated 12 | RecordNotFound = ActiveMocker::RecordNotFound 13 | end 14 | 15 | class IdError < BaseError 16 | end 17 | 18 | # Raised when unknown attributes are supplied via mass assignment. 19 | class UnknownAttributeError < NoMethodError 20 | attr_reader :record, :attribute 21 | 22 | def initialize(record, attribute) 23 | @record = record 24 | @attribute = attribute.to_s 25 | super("unknown attribute: #{attribute}") 26 | end 27 | end 28 | 29 | class UpdateMocksError < BaseError 30 | def initialize(name, mock_build_version, mock_current_version) 31 | super("#{name} was built with #{mock_build_version} but the mock current version is #{mock_current_version}. Run `rake active_mocker:build` to update.") 32 | end 33 | end 34 | 35 | class NotImplementedError < BaseError 36 | end 37 | 38 | class Error < BaseError 39 | end 40 | 41 | class MockNotLoaded < BaseError 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/has_and_belongs_to_many.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class HasAndBelongsToMany < HasMany 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/has_many.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class HasMany < Association 4 | include Queries 5 | 6 | def self.new(collection, options = {}) 7 | return Relation.new(collection) if options[:relation_class].nil? 8 | super(collection, options) 9 | end 10 | 11 | def initialize(collection, options = {}) 12 | @relation_class = options[:relation_class] 13 | @foreign_key = options[:foreign_key] 14 | @foreign_id = options[:foreign_id] 15 | @source = options[:source] 16 | self.class.include "#{@relation_class.name}::Scopes".constantize 17 | super(collection) 18 | set_foreign_key 19 | end 20 | 21 | def set_foreign_key 22 | collection.each do |item| 23 | item.send(:write_attribute, foreign_key, foreign_id) if item.respond_to?("#{foreign_key}=") 24 | end 25 | end 26 | 27 | # @api private 28 | attr_reader :relation_class, :foreign_key, :foreign_id, :source 29 | 30 | def build(options = {}, &block) 31 | new_record = relation_class.new(init_options.merge!(options), &block) 32 | 33 | # @private 34 | def new_record._belongs_to(collection) 35 | @belongs_to_collection = collection 36 | end 37 | 38 | new_record._belongs_to(self) 39 | 40 | # @private 41 | def new_record.save 42 | @belongs_to_collection << self 43 | super 44 | end 45 | 46 | new_record 47 | end 48 | 49 | def create(options = {}, &block) 50 | created_record = relation_class.create(init_options.merge!(options), &block) 51 | collection << created_record 52 | created_record 53 | end 54 | 55 | alias create! create 56 | 57 | # @api private 58 | def init_options 59 | { foreign_key => foreign_id } 60 | end 61 | end 62 | module Mock 63 | # @deprecated 64 | HasMany = ActiveMocker::HasMany 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/has_one.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class HasOne < SingleRelation 4 | attr_reader :item 5 | 6 | def initialize(item, child_self:, foreign_key:) 7 | item.send(:write_attribute, foreign_key, item.try(:id)) unless item.try(:id).nil? 8 | super 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/hash_process.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | # @api private 4 | class HashProcess 5 | attr_accessor :hash, :processor 6 | 7 | def initialize(hash, processor) 8 | @hash = hash 9 | @processor = processor 10 | @hash_process = {} 11 | end 12 | 13 | def [](val) 14 | @hash_process[val] ||= processor.call(hash[val]) 15 | end 16 | 17 | def merge(merge_hash) 18 | self.hash = hash.merge(merge_hash.hash) 19 | self 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/mock_relation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class MockRelation 4 | # @param [ActiveMocker::Base] mock, a generated mock class 5 | # @param [Array] collection, an array of mock instances 6 | # @return [ScopeRelation] for the given mock 7 | def self.new(mock, collection) 8 | mock.send(:__new_relation__, collection) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/mockable_method.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveMocker 4 | module MockableMethod 5 | private 6 | 7 | def __am_raise_not_mocked_error(method:, caller:, type:) 8 | variable_name, klass, method_type = if is_a?(Relation) 9 | klass = self.class.name.underscore.split("/").first 10 | ["#{klass}_relation", klass.camelize, :scopes] 11 | elsif type == "#" 12 | klass = self.class.name 13 | ["#{klass.underscore.split("/").first}_record", klass, :instance_methods] 14 | else 15 | [name, name, :class_methods] 16 | end 17 | 18 | message = <<-ERROR.strip_heredoc 19 | Unknown implementation for mock method: #{variable_name}.#{method} 20 | Stub method to continue. 21 | 22 | RSpec: 23 | allow( 24 | #{variable_name} 25 | ).to receive(:#{method}).and_return(:some_expected_result) 26 | 27 | OR Whitelist the method as safe to copy/run in the context of ActiveMocker (requires mock rebuild) 28 | # ActiveMocker.safe_methods #{method_type}: [:#{method}] 29 | class #{klass.gsub("Mock", "")} < ActiveRecord::Base 30 | end 31 | ERROR 32 | 33 | raise NotImplementedError, message, caller 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/object_inspect.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class ObjectInspect 4 | def initialize(class_name, attributes) 5 | @class_name = class_name 6 | @attributes = attributes 7 | @string = create_inspections 8 | end 9 | 10 | def to_s 11 | @string 12 | end 13 | 14 | def to_str 15 | @string 16 | end 17 | 18 | private 19 | 20 | def create_inspections 21 | inspection = @attributes.map do |name, value| 22 | "#{name}: #{object_for_inspect(value)}" 23 | end 24 | "#<#{@class_name} #{inspection.compact.join(", ")}>" 25 | end 26 | 27 | def object_for_inspect(value) 28 | if value.is_a?(String) && value.length > 50 29 | "#{value[0, 50]}...".inspect 30 | elsif value.is_a?(Date) || value.is_a?(Time) 31 | %("#{value.to_s(:db)}") 32 | elsif value.is_a?(Array) && value.size > 10 33 | inspected = value.first(10).inspect 34 | %(#{inspected[0...-1]}, ...]) 35 | else 36 | value.inspect 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/records.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Records 4 | extend Forwardable 5 | def_delegators :records, :<<, :count, :length, :to_a 6 | 7 | attr_reader :records 8 | private :records 9 | 10 | def initialize(records = []) 11 | @records = records 12 | end 13 | 14 | def insert(record) 15 | records << validate_id((record.id ||= next_id), record) 16 | end 17 | 18 | def delete(record) 19 | raise RecordNotFound, "Record has not been created." unless records.delete(record) 20 | end 21 | 22 | def exists?(record) 23 | records.include?(record) 24 | end 25 | 26 | def new_record?(record) 27 | !exists?(record) 28 | end 29 | 30 | def persisted?(id) 31 | ids.include?(id) 32 | end 33 | 34 | def reset 35 | records.clear 36 | end 37 | 38 | private 39 | 40 | def ids 41 | records.map(&:id) 42 | end 43 | 44 | def next_id 45 | max_record.succ 46 | rescue NoMethodError 47 | 1 48 | end 49 | 50 | def max_record 51 | ids.max 52 | end 53 | 54 | def validate_id(id, record) 55 | record.id = id.to_i 56 | validate_unique_id(id, record) 57 | end 58 | 59 | def validate_unique_id(id, record) 60 | raise IdError, "Duplicate ID found for record #{record.inspect}" if persisted?(id) 61 | record 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/relation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Relation < Collection 4 | include Queries 5 | include MockableMethod 6 | 7 | def initialize(collection = []) 8 | super 9 | @from_limit = false 10 | end 11 | 12 | def inspect 13 | entries = to_a.take(11).map!(&:inspect) 14 | entries[10] = "..." if entries.size == 11 15 | "#<#{name} [#{entries.join(", ")}]>" 16 | end 17 | 18 | def from_limit? 19 | @from_limit 20 | end 21 | 22 | def name 23 | self.class.name 24 | end 25 | 26 | private 27 | 28 | def set_from_limit 29 | @from_limit = true 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/single_relation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class SingleRelation 4 | attr_reader :item 5 | 6 | def initialize(item, child_self:, foreign_key:) 7 | @item = item 8 | assign_associations(child_self, item) if item.class <= Base 9 | end 10 | 11 | def assign_associations(child_self, item) 12 | [*item.class._find_associations_by_class(child_self.class.send("mocked_class"))].each do |_type, relations| 13 | relations.each do |relation| 14 | if item.send(relation).class <= Collection 15 | item.send(relation) << child_self 16 | else 17 | item.send(:write_association, relation, child_self) 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/template_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module TemplateMethods 4 | def self.included(base) 5 | base.extend(ClassMethods) 6 | end 7 | 8 | module ClassMethods 9 | def attributes 10 | HashWithIndifferentAccess.new({}) 11 | end 12 | 13 | def types 14 | HashProcess.new({}, method(:build_type)) 15 | end 16 | 17 | def associations 18 | {} 19 | end 20 | 21 | def associations_by_class 22 | {} 23 | end 24 | 25 | def mocked_class 26 | "" 27 | end 28 | 29 | def attribute_names 30 | [] 31 | end 32 | 33 | def primary_key 34 | "" 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/active_mocker/mock/unrepresentable_const_value.rb: -------------------------------------------------------------------------------- 1 | module ActiveMocker 2 | UNREPRESENTABLE_CONST_VALUE = "ActiveMocker can not determine the value, if needed stub this const with a valid test value".freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/associations.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class MockCreator 4 | module Associations 5 | def has_many 6 | relation_find(:type, __method__) 7 | end 8 | 9 | def has_one 10 | relation_find(:type, __method__) 11 | end 12 | 13 | def belongs_to 14 | relation_find(:type, __method__) 15 | end 16 | 17 | def has_and_belongs_to_many 18 | relation_find(:type, __method__) 19 | end 20 | 21 | def relation_find(key, value) 22 | association_collection.select { |r| r.send(key).to_sym == value } 23 | end 24 | 25 | def association_collection 26 | @association_collection ||= schema_scrapper.associations.to_a 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class MockCreator 4 | module Attributes 5 | def attributes 6 | @attributes ||= begin 7 | a = schema_scrapper.attributes.to_a 8 | a << primary_key unless a.any? { |aa| aa.name == "id" } 9 | a.map(&method(:process_attr)) 10 | a 11 | end 12 | end 13 | 14 | def process_attr(attr) 15 | enums = enums(attr.name) 16 | attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default) 17 | attr.attribute_writer = "write_attribute(:#{attr.name}, val)" 18 | attr.attribute_reader = "read_attribute(:#{attr.name})" 19 | 20 | unless enums.empty? 21 | enum_type = ActiveMocker::AttributeTypes::Enum.build( 22 | enums: enums, 23 | table_name: table_name, 24 | attribute: attr.name, 25 | db_value_type: attr.type, 26 | ) 27 | if ActiveRecord::VERSION::MAJOR >= 5 28 | enum_type.ignore_value = true 29 | attr.type = enum_type 30 | if attr.default 31 | attr.default = Virtus::Attribute.build(enum_type).get_key(attr.default) 32 | end 33 | elsif ActiveRecord::VERSION::MAJOR == 4 34 | attr.attribute_writer = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\nwrite_attribute(:#{attr.name}, @#{attr.name}_enum_type.coerce(val))" 35 | attr.attribute_reader = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\n@#{attr.name}_enum_type.get_key(read_attribute(:#{attr.name}))" 36 | if attr.default 37 | attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default) 38 | end 39 | end 40 | attr 41 | end 42 | end 43 | 44 | def enums(attribute) 45 | @enums ||= begin 46 | raw_enums = class_introspector 47 | .class_macros 48 | .select { |hash| hash.key?(:enum) } 49 | if raw_enums 50 | raw_enums 51 | .map { |hash| hash[:enum].flatten.first } 52 | .each_with_object({}) { |v, h| h.merge!(v) } 53 | else 54 | {} 55 | end 56 | end 57 | 58 | @enums.fetch(attribute.to_sym, {}) 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/class_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative "attributes" 3 | 4 | module ActiveMocker 5 | class MockCreator 6 | module ClassMethods 7 | include Attributes 8 | 9 | def attributes_with_defaults 10 | types_hash 11 | attributes.each_with_object({}) do |attr, hash| 12 | hash[attr.name] = attr.default 13 | end 14 | end 15 | 16 | def types_hash 17 | @types_hash ||= attributes.each_with_object(HashNewStyle.new) do |attr, types| 18 | types[attr.name] = attr.type.to_s 19 | end.inspect 20 | end 21 | 22 | def associations 23 | @associations ||= schema_scrapper.associations.to_a.each_with_object({}) do |a, h| 24 | h[a.name] = nil 25 | end 26 | end 27 | 28 | def associations_by_class 29 | schema_scrapper.associations.to_a.each_with_object({}) do |r, hash| 30 | hash[r.class_name.to_s] ||= {} 31 | hash[r.class_name.to_s][r.type] ||= [] 32 | hash[r.class_name.to_s][r.type] << r.name 33 | end 34 | end 35 | 36 | def attribute_names 37 | attributes.map(&:name) 38 | end 39 | 40 | def abstract_class 41 | schema_scrapper.abstract_class? 42 | end 43 | 44 | def table_name 45 | schema_scrapper.table_name 46 | end 47 | 48 | def mocked_class 49 | [nested_modules, class_name].compact.reject(&:empty?).join("::") 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/defined_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require_relative "safe_methods" 3 | module ActiveMocker 4 | class MockCreator 5 | module DefinedMethods 6 | include SafeMethods 7 | Method = Struct.new(:name, :arguments, :body) 8 | 9 | def instance_methods 10 | meths = class_introspector.get_class.public_instance_methods(false).sort 11 | meths << :initialize if safe_methods[:instance_methods].include?(:initialize) 12 | meths.map { |m| create_method(m, :instance_method) } 13 | end 14 | 15 | def class_methods 16 | class_introspector 17 | .get_class 18 | .methods(false) 19 | .sort 20 | .map { |m| create_method(m, :method) } 21 | end 22 | 23 | private 24 | 25 | def create_method(m, type) 26 | plural_type = (type.to_s + "s").to_sym 27 | if safe_method?(type, m) 28 | def_type = type == :method ? :class_defs : :defs 29 | def_method = class_introspector.parsed_source.public_send(def_type).detect { |meth| meth.name == m } 30 | raise "ActiveMocker.safe_methods is unable to find #{plural_type}: #{m}" unless def_method 31 | Method.new( 32 | m, 33 | def_method.arguments, 34 | def_method.body 35 | ) 36 | else 37 | type_symbol = type == :method ? "::" : "#" 38 | Method.new( 39 | m, 40 | ReverseParameters.new( 41 | class_introspector.get_class.send(type, m).parameters 42 | ).parameters, 43 | "__am_raise_not_mocked_error(method: __method__, caller: Kernel.caller, type: '#{type_symbol}')" 44 | ) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/mock_build_version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveMocker 4 | class MockCreator 5 | module MockBuildVersion 6 | def mock_build_version 7 | "mock_build_version #{ActiveMocker::Mock::VERSION.inspect}, active_record: '#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}'" 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_creator/modules_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class MockCreator 4 | module ModulesConstants 5 | class Inspectable 6 | attr_reader :inspect 7 | 8 | def initialize(inspect) 9 | @inspect = inspect 10 | end 11 | end 12 | 13 | def modules 14 | @modules ||= begin 15 | { 16 | included: get_module_by_reference(:included_modules), 17 | extended: get_module_by_reference(:extended_modules), 18 | } 19 | end 20 | end 21 | 22 | def constants 23 | class_introspector.get_class.constants.map do |v| 24 | c = class_introspector.get_class.const_get(v) 25 | next if [Module, Class].include?(c.class) 26 | const = if /\A# < <%= parent_class_inspector.parent_mock_name %> 4 | 5 | <%= partials.mock_build_version %> 6 | <%= partials.modules_constants %> 7 | <%= partials.class_methods %> 8 | <%= partials.attributes %> 9 | <%= partials.associations %> 10 | <%= partials.recreate_class_method_calls %> 11 | <%= partials.defined_methods %> 12 | <%= partials.scopes %> 13 | end 14 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_associations.erb: -------------------------------------------------------------------------------- 1 | # _associations.erb 2 | 3 | <%= '# belongs_to' unless belongs_to.empty? -%> 4 | 5 | <% belongs_to.each do |meth| -%> 6 | def <%= meth.name %> 7 | <% association = relation_find(:name, meth.name).first -%> 8 | read_association(:<%= meth.name %>) || write_association(:<%= meth.name %>, classes('<%= association.class_name %>').try{ |k| k.find_by(id: <%= association.foreign_key %>)}) 9 | end 10 | def <%= meth.name %>=(val) 11 | write_association(:<%= meth.name %>, val) 12 | ActiveMocker::BelongsTo.new(val, child_self: self, foreign_key: :<%= meth.foreign_key %>).item 13 | end 14 | 15 | def build_<%= meth.name %>(attributes={}, &block) 16 | <% association = relation_find(:name, meth.name).first -%> 17 | <% if association -%> 18 | self.<%= meth.name %> = classes('<%= association.class_name %>', true).new(attributes, &block) 19 | <% end -%> 20 | end 21 | 22 | def create_<%= meth.name %>(attributes={}, &block) 23 | <% association = relation_find(:name, meth.name).first -%> 24 | <% if association -%> 25 | self.<%= meth.name %> = classes('<%= association.class_name %>', true).create(attributes, &block) 26 | <% end -%> 27 | end 28 | alias_method :create_<%= meth.name %>!, :create_<%= meth.name %> 29 | <% end -%> 30 | 31 | <%= '# has_one' unless has_one.empty? -%> 32 | 33 | <% has_one.each do |meth| -%> 34 | def <%= meth.name %> 35 | read_association(:<%= meth.name %>) 36 | end 37 | 38 | def <%= meth.name %>=(val) 39 | write_association(:<%= meth.name %>, val) 40 | ActiveMocker::HasOne.new(val, child_self: self, foreign_key: '<%= meth.foreign_key %>').item 41 | end 42 | 43 | def build_<%= meth.name %>(attributes={}, &block) 44 | <% association = relation_find(:name, meth.name).first -%> 45 | <% if association -%> 46 | self.<%= meth.name %>= classes('<%= association.class_name %>', true).new(attributes, &block) 47 | <% end -%> 48 | end 49 | 50 | def create_<%= meth.name %>(attributes={}, &block) 51 | <% association = relation_find(:name, meth.name).first -%> 52 | <% if association -%> 53 | self.<%= meth.name %>= classes('<%= association.class_name %>', true).new(attributes, &block) 54 | <% end -%> 55 | end 56 | alias_method :create_<%= meth.name %>!, :create_<%= meth.name %> 57 | <% end -%> 58 | 59 | <%= '# has_many' unless has_many.empty? -%> 60 | 61 | <% has_many.each do |meth| -%> 62 | def <%= meth.name %> 63 | read_association(:<%= meth.name %>, -> { ActiveMocker::HasMany.new([],foreign_key: '<%= meth.foreign_key %>', foreign_id: self.id, relation_class: classes('<%= meth.class_name %>'), source: '<%= meth.source %>') }) 64 | end 65 | 66 | def <%= meth.name %>=(val) 67 | write_association(:<%= meth.name %>, ActiveMocker::HasMany.new(val, foreign_key: '<%= meth.foreign_key %>', foreign_id: self.id, relation_class: classes('<%= meth.class_name %>'), source: '<%= meth.source %>')) 68 | end 69 | <% end -%> 70 | <%= '# has_and_belongs_to_many' unless has_and_belongs_to_many.empty? -%> 71 | 72 | <% has_and_belongs_to_many.each do |meth| -%> 73 | def <%= meth.name %> 74 | read_association(:<%= meth.name %>, -> { ActiveMocker::HasAndBelongsToMany.new([],foreign_key: '<%= meth.foreign_key %>', foreign_id: self.id, relation_class: classes('<%= meth.class_name %>'), source: '<%= meth.source %>') }) 75 | end 76 | 77 | def <%= meth.name %>=(val) 78 | write_association(:<%= meth.name %>, ActiveMocker::HasAndBelongsToMany.new(val, foreign_key: '<%= meth.foreign_key %>', foreign_id: self.id, relation_class: classes('<%= meth.class_name %>'), source: '<%= meth.source %>')) 79 | end 80 | <% end -%> 81 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_attributes.erb: -------------------------------------------------------------------------------- 1 | # _attributes.erb 2 | <% attributes.each do |meth| -%> 3 | def <%= meth.name %> 4 | <%= meth.attribute_reader %> 5 | end 6 | 7 | 8 | def <%= meth.name %>=(val) 9 | <%= meth.attribute_writer %> 10 | end 11 | <% end -%> 12 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_class_methods.erb: -------------------------------------------------------------------------------- 1 | #_class_methods.erb 2 | class << self 3 | private 4 | 5 | def attributes 6 | @attributes ||= HashWithIndifferentAccess.new(<%= attributes_with_defaults.map {|key,value| %Q[#{key}: #{value.inspect}]}.join(", ") %>).merge(super) 7 | end 8 | 9 | def types 10 | @types ||= ActiveMocker::HashProcess.new(<%= types_hash %>, method(:build_type)).merge(super) 11 | end 12 | 13 | def associations 14 | @associations ||= <%= associations %>.merge(super) 15 | end 16 | 17 | def associations_by_class 18 | @associations_by_class ||= <%= associations_by_class %>.merge(super) 19 | end 20 | 21 | def mocked_class 22 | <%= mocked_class.inspect %> 23 | end 24 | 25 | public 26 | 27 | def attribute_names 28 | @attribute_names ||= attributes.stringify_keys.keys 29 | end 30 | 31 | def primary_key 32 | <%= primary_key.name.inspect %> 33 | end 34 | 35 | def abstract_class? 36 | <%= abstract_class.inspect %> 37 | end 38 | 39 | def table_name 40 | <%= table_name.inspect %> || super 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_defined_methods.erb: -------------------------------------------------------------------------------- 1 | <% instance_methods.each do |method| -%> 2 | def <%= method.name %><%= "(#{method.arguments})" unless method.arguments.blank? %> 3 | <%= method.body %> 4 | end 5 | <% end -%> 6 | module ClassMethods 7 | <% class_methods.each do |method| -%> 8 | def <%= method.name %><%= "(#{method.arguments})" unless method.arguments.blank? %> 9 | <%= method.body %> 10 | end 11 | <% end -%> 12 | end 13 | 14 | extend ClassMethods 15 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_mock_build_version.erb: -------------------------------------------------------------------------------- 1 | <%= mock_build_version %> 2 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_modules_constants.erb: -------------------------------------------------------------------------------- 1 | # _modules_constants.erb 2 | <% constants.each do |constant, value| -%> 3 | <%= constant %> = <%= value.inspect %> 4 | <% end -%> 5 | <% modules[:included].each do |constant| -%> 6 | prepend <%= constant %> 7 | <% end -%> 8 | <% modules[:extended].each do |constant| -%> 9 | extend <%= constant %> 10 | <% end -%> 11 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_recreate_class_method_calls.erb: -------------------------------------------------------------------------------- 1 | # _recreate_class_method_calls.erb 2 | 3 | def self.attribute_aliases 4 | @attribute_aliases ||= <%= attribute_aliases %>.merge(super) 5 | end 6 | 7 | <% class_method_calls.each do |method| -%> 8 | alias_method :<%= method.new_name %>, :<%= method.old_name %> 9 | alias_method :<%= method.new_name %>=, :<%= method.old_name %>= 10 | 11 | <% end -%> 12 | 13 | -------------------------------------------------------------------------------- /lib/active_mocker/mock_template/_scopes.erb: -------------------------------------------------------------------------------- 1 | # _scopes.erb 2 | module Scopes 3 | include <%= parent_class_inspector.parent_mock_name %>::Scopes 4 | 5 | <% scope_methods.each do |method| -%> 6 | def <%= method.name %><%= "(#{method.arguments.parameters})" unless method.arguments.parameters.to_a.empty? %> 7 | <%= method.body %> 8 | end 9 | 10 | <% end -%> 11 | end 12 | 13 | extend Scopes 14 | 15 | class ScopeRelation < ActiveMocker::Association 16 | include <%= class_name + mock_append_name %>::Scopes 17 | include ClassMethods 18 | end 19 | 20 | def self.__new_relation__(collection) 21 | <%= class_name + mock_append_name %>::ScopeRelation.new(collection) 22 | end 23 | 24 | private_class_method :__new_relation__ 25 | -------------------------------------------------------------------------------- /lib/active_mocker/null_progress.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class NullProgress 4 | def self.create(*) 5 | new 6 | end 7 | 8 | def initialize(*) 9 | end 10 | 11 | def increment 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/active_mocker/parent_class.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class ParentClass 4 | def initialize(parsed_source:, klasses_to_be_mocked:, mock_append_name:, active_record_base_klass: ::ActiveRecord::Base) 5 | @parsed_source = parsed_source 6 | @klasses_to_be_mocked = klasses_to_be_mocked 7 | @active_record_base_klass = active_record_base_klass 8 | @mock_append_name = mock_append_name 9 | end 10 | 11 | attr_reader :error 12 | 13 | def call 14 | if parent_class? 15 | deal_with_parent 16 | else 17 | create_error("#{class_name} is missing a parent class.") 18 | end 19 | self 20 | end 21 | 22 | def parent_mock_name 23 | if @parent_mock_name 24 | "#{@parent_mock_name}#{mock_append_name}" 25 | else 26 | "ActiveMocker::Base" 27 | end 28 | end 29 | 30 | private 31 | 32 | attr_reader :parsed_source, 33 | :klasses_to_be_mocked, 34 | :active_record_base_klass, 35 | :mock_append_name 36 | 37 | def deal_with_parent 38 | if parent_class <= active_record_base_klass 39 | @parent_mock_name = parent_class_name if included_mocked_class? 40 | else 41 | create_error("#{class_name} does not inherit from ActiveRecord::Base") 42 | end 43 | end 44 | 45 | def create_error(message) 46 | @error = OpenStruct.new(class_name: class_name, 47 | message: message) 48 | end 49 | 50 | def parent_class? 51 | parsed_source.parent_class? 52 | end 53 | 54 | def parent_class_name 55 | parsed_source.parent_class_name 56 | end 57 | 58 | def class_name 59 | parsed_source.class_name 60 | end 61 | 62 | def parent_class 63 | parent_class_name.constantize 64 | end 65 | 66 | def included_mocked_class? 67 | sanitize_consts(klasses_to_be_mocked).include?(sanitize_consts(parent_class_name).first) 68 | end 69 | 70 | def sanitize_consts(consts) 71 | [*consts].map do |const| 72 | const.split("::").reject(&:empty?).join("::") 73 | end 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /lib/active_mocker/progress.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Progress 4 | def self.create(count) 5 | require "ruby-progressbar" 6 | new(count) 7 | rescue LoadError 8 | NullProgress.new 9 | end 10 | 11 | def initialize(count) 12 | @count = count 13 | end 14 | 15 | delegate :increment, to: :progress 16 | 17 | def progress 18 | @progress ||= ProgressBar.create(title: "Generating Mocks", 19 | total: @count, 20 | format: "%t |%b>>%i| %p%%") 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_mocker/public_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class << self 4 | # Override default Configurations 5 | # 6 | # ActiveMocker.configure do |c| 7 | # c.model_dir= # Directory of ActiveRecord models 8 | # c.mock_dir= # Directory to save mocks 9 | # c.single_model_path= # Path to generate a single mock 10 | # c.progress_bar= # False disables progress bar from sending to STDOUT 11 | # or pass a class that takes a count in the initializer and responds to #increment. 12 | # c.error_verbosity= # 0 = none 13 | # # 1 = Summary of failures 14 | # # 2 = One line per error 15 | # # 3 = Errors with exception backtrace 16 | # c.disable_modules_and_constants= # Modules are include/extend along with constant declarations. 17 | # # Default is false, to disable set to true. 18 | # end 19 | # 20 | # @returns self 21 | # @yield [Config] 22 | def configure(&block) 23 | Config.set(&block) 24 | self 25 | end 26 | alias config configure 27 | 28 | # Generates Mocks file 29 | # @returns self 30 | def create_mocks 31 | Generate.new.call 32 | self 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/active_mocker/railtie.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | class Railtie < Rails::Railtie 4 | rake_tasks do 5 | load "active_mocker/task.rake" 6 | end 7 | 8 | config.to_prepare do 9 | ActiveMocker::Config.load_defaults 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/active_mocker/rspec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | module Rspec 4 | # @return ActiveMocker::LoadedMocks 5 | def active_mocker 6 | ActiveMocker::LoadedMocks 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/active_mocker/rspec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "active_mocker/loaded_mocks" 3 | require "active_mocker/rspec" 4 | 5 | RSpec.configure do |config| 6 | config.include ActiveMocker::Rspec 7 | 8 | config.before(:each, active_mocker: true) do 9 | unless ENV["RUN_WITH_RAILS"] && self.class.metadata[:rails_compatible] 10 | active_mocker.mocks.each { |class_name, mock| stub_const(class_name, mock) } 11 | end 12 | if (mapping = active_mocker.features[:stub_active_record_exceptions]) 13 | mapping.each { |class_name, mock| stub_const(class_name, mock) } 14 | end 15 | end 16 | 17 | config.after(:all, active_mocker: true) do 18 | ActiveMocker::LoadedMocks.delete_all 19 | end 20 | 21 | config.before(:all, active_mocker: true) do 22 | ActiveMocker::LoadedMocks.delete_all 23 | end 24 | 25 | config.after(:each, active_mocker: true) do 26 | ActiveMocker::LoadedMocks.delete_all if active_mocker.features[:delete_all_before_example] 27 | end 28 | 29 | config.before(:each, active_mocker: true) do 30 | ActiveMocker::LoadedMocks.delete_all if active_mocker.features[:delete_all_before_example] 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/active_mocker/task.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | namespace :active_mocker do 3 | desc("Rebuild mocks.") 4 | task build: :environment do 5 | ActiveMocker.configure do |c| 6 | c.single_model_path = ENV["MODEL"] if ENV["MODEL"] 7 | c.model_dir = ENV["MODEL_DIR"] if ENV["MODEL_DIR"] 8 | c.mock_dir = ENV["MOCK_DIR"] if ENV["MOCK_DIR"] 9 | c.progress_bar = false if ENV["MUTE_PROGRESS_BAR"] 10 | c.error_verbosity = ENV["ERROR_VERBOSITY"].to_i if ENV["ERROR_VERBOSITY"] 11 | c.disable_modules_and_constants = false 12 | end.create_mocks 13 | end 14 | 15 | desc("Run all tests tagged active_mocker") 16 | task :test do 17 | sh "rspec --tag active_mocker" 18 | end 19 | 20 | desc("Run all tests tagged active_mocker and rails_compatible and will disable model stubbing") 21 | task :rails_compatible do 22 | sh "RUN_WITH_RAILS=1 rspec --tag rails_compatible" 23 | end 24 | end 25 | 26 | ["db:migrate", "db:rollback"].each do |task| 27 | Rake::Task[task].enhance do 28 | Rake::Task["active_mocker:build"].invoke 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/active_mocker/template_creator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "forwardable" 3 | 4 | module ActiveMocker 5 | class TemplateCreator 6 | def initialize(erb_template:, file_out: nil, binding:, post_process: -> (str) { str }) 7 | @erb_template = erb_template 8 | @binding = binding 9 | @file_out = file_out || Tempfile.new("TemplateModel") 10 | @post_process = post_process 11 | end 12 | 13 | def render 14 | template = ERB.new(erb_template.read, nil, ">") 15 | file_out.write post_process.call(template.result(binding)) 16 | file_out 17 | end 18 | 19 | private 20 | 21 | attr_reader :erb_template, :binding, :file_out, :post_process 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_mocker/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveMocker 3 | VERSION = "2.6.2" 4 | module Mock 5 | VERSION = "2" # This increments when breaking changes happen in the generated mocks 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/log/.keep -------------------------------------------------------------------------------- /spec/gemfile_version_match_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | RSpec.describe "Gemfile Version Match" do 3 | it "rails_4.2.gemfile.lock" do 4 | file = File.join(File.expand_path("../../", __FILE__), "test_rails_app/gemfiles/rails_4.2.gemfile.lock") 5 | expect(!File.readlines(file).grep(/active_mocker \(#{Regexp.quote(ActiveMocker::VERSION)}\)/).empty?).to eq true 6 | end 7 | 8 | it "rails_5.2.gemfile.lock" do 9 | file = File.join(File.expand_path("../../", __FILE__), "test_rails_app/gemfiles/rails_5.2.gemfile.lock") 10 | expect(!File.readlines(file).grep(/active_mocker \(#{Regexp.quote(ActiveMocker::VERSION)}\)/).empty?).to eq true 11 | end 12 | 13 | it "rails_6.0.gemfile.lock" do 14 | file = File.join(File.expand_path("../../", __FILE__), "test_rails_app/gemfiles/rails_6.0.gemfile.lock") 15 | expect(!File.readlines(file).grep(/active_mocker \(#{Regexp.quote(ActiveMocker::VERSION)}\)/).empty?).to eq true 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/config_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "logger" 4 | require "active_mocker/config" 5 | 6 | describe ActiveMocker::Config do 7 | after do 8 | described_class.reset_all 9 | described_class.load_defaults 10 | end 11 | 12 | before do 13 | described_class.reset_all 14 | described_class.load_defaults 15 | end 16 | 17 | it do 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/file_path_to_ruby_class_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/file_path_to_ruby_class" 4 | require "active_support/core_ext/string" 5 | 6 | RSpec.describe ActiveMocker::FilePathToRubyClass do 7 | describe "#to_s" do 8 | subject do 9 | described_class.new(base_path: base_path, 10 | class_path: class_path).to_s 11 | end 12 | 13 | context "single class" do 14 | let(:base_path) { "user/my_app/models" } 15 | let(:class_path) { "user/my_app/models/user.rb" } 16 | 17 | it { expect(subject).to eq "User" } 18 | end 19 | 20 | context "one deep namespaced class" do 21 | let(:base_path) { "user/my_app/models" } 22 | let(:class_path) { "user/my_app/models/api/user.rb" } 23 | 24 | it { expect(subject).to eq "Api::User" } 25 | end 26 | 27 | context "two deep namespaced class" do 28 | let(:base_path) { "user/my_app/models" } 29 | let(:class_path) { "user/my_app/models/api/b/user.rb" } 30 | 31 | it { expect(subject).to eq "Api::B::User" } 32 | end 33 | 34 | context "three deep namespaced class" do 35 | let(:base_path) { "user/my_app/models" } 36 | let(:class_path) { "user/my_app/models/api/b/c/user.rb" } 37 | 38 | it { expect(subject).to eq "Api::B::C::User" } 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/association_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/queries" 4 | require "active_mocker/mock/collection" 5 | require "active_mocker/mock/mockable_method" 6 | require "active_mocker/mock/relation" 7 | require "active_mocker/mock/association" 8 | require "active_mocker/mock/has_many" 9 | require "ostruct" 10 | require_relative "has_many_shared_example" 11 | require_relative "queriable_shared_example" 12 | 13 | describe ActiveMocker::Association do 14 | it_behaves_like "Queriable", -> (*args) { described_class.new(args.flatten) } 15 | end 16 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/base_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "logger" 4 | require "active_mocker/mock" 5 | require_relative "queriable_shared_example" 6 | require "active_mocker/mock/exceptions" 7 | describe ActiveMocker::Base do 8 | class ActiveMocker::Base 9 | class << self 10 | def abstract_class? 11 | false 12 | end 13 | 14 | attr_writer :records 15 | end 16 | 17 | def id 18 | self.class.attributes[:id] 19 | end 20 | 21 | def id=(val) 22 | self.class.attributes[:id] = val 23 | end 24 | end 25 | 26 | it_behaves_like "Queriable", -> (*args) { 27 | ActiveMocker::Base.clear_mock 28 | ActiveMocker::Base.send(:records=, ActiveMocker::Records.new(args.flatten)) 29 | ActiveMocker::Base 30 | } 31 | 32 | describe "destroy" do 33 | subject { described_class.create } 34 | 35 | it "will delegate to delete" do 36 | subject.destroy 37 | expect(described_class.count).to eq 0 38 | end 39 | end 40 | 41 | describe "::_find_associations_by_class" do 42 | it do 43 | allow(ActiveMocker::Base).to receive(:associations_by_class) { { "User" => [:customers] } } 44 | result = described_class._find_associations_by_class("User") 45 | expect(result).to eq [:customers] 46 | end 47 | end 48 | 49 | describe "::classes" do 50 | it "raises an error if not loaded" do 51 | expect{described_class.send(:classes, "Abc", true)}.to raise_error(ActiveMocker::MockNotLoaded, "The ActiveMocker version of Abc is not required.") 52 | end 53 | end 54 | 55 | before do 56 | described_class.delete_all 57 | end 58 | 59 | after do 60 | described_class.delete_all 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/belongs_to_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock" 4 | require "active_mocker/mock/belongs_to" 5 | describe ActiveMocker::BelongsTo do 6 | it "item can be an non ActiveMock that does not respond to save" do 7 | described_class.new(double("NonActiveMocker"), child_self: double("ActiveMocker", persisted?: true, write_attribute: true), foreign_key: 1) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/collection_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/collection" 4 | 5 | describe ActiveMocker::Collection do 6 | describe '#<<' do 7 | it "will add a single item to the array" do 8 | subject << "item" 9 | expect(subject.count).to eq 1 10 | expect(subject.first).to eq "item" 11 | end 12 | 13 | it "will add a many item to the array" do 14 | subject << %w(item1 item2 item3) 15 | expect(subject.count).to eq 3 16 | expect(subject).to eq %w(item1 item2 item3) 17 | end 18 | end 19 | 20 | describe "empty?" do 21 | it "returns true if collection is empty" do 22 | expect(subject.empty?).to eq true 23 | end 24 | 25 | it "returns false if collection is not empty" do 26 | subject << 1 27 | expect(subject.empty?).to eq false 28 | end 29 | end 30 | 31 | describe "each" do 32 | it "can iterate over array" do 33 | sum = 0 34 | described_class.new([1, 2]).each { |a| sum += a } 35 | expect(sum).to eq 3 36 | end 37 | end 38 | 39 | describe "map" do 40 | it "return a new array" do 41 | expect(described_class.new([1, 2]).map { |a| a + a }).to eq [2, 4] 42 | end 43 | 44 | it "return an instance of the class" do 45 | expect(described_class.new([1, 2]).map { |a| a + a }).to be_a_kind_of Array 46 | end 47 | end 48 | 49 | describe "[]" do 50 | it "can get an item from the array" do 51 | expect(described_class.new([1, 2])[0]).to eq 1 52 | end 53 | 54 | it "can get a range of items from the array" do 55 | expect(described_class.new([1, 2])[0..1]).to eq [1, 2] 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/has_and_belongs_to_many_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/collection" 4 | require "active_mocker/mock/queries" 5 | require "active_mocker/mock/relation" 6 | require "active_mocker/mock/association" 7 | require "active_mocker/mock/has_many" 8 | require "active_mocker/mock/has_and_belongs_to_many" 9 | require "active_mocker/mock" 10 | require "ostruct" 11 | require "active_support/inflector" 12 | require_relative "has_many_shared_example" 13 | require_relative "queriable_shared_example" 14 | 15 | describe ActiveMocker::HasAndBelongsToMany do 16 | it_behaves_like "HasMany" 17 | it_behaves_like "Queriable", -> (*args) { described_class.new(args.flatten) } 18 | end 19 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/has_many_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/queries" 4 | require "active_mocker/mock/collection" 5 | require "active_mocker/mock/relation" 6 | require "active_mocker/mock/association" 7 | require "active_mocker/mock/has_many" 8 | require "active_mocker/mock" 9 | require "ostruct" 10 | require "active_support/inflector" 11 | require_relative "has_many_shared_example" 12 | require_relative "queriable_shared_example" 13 | 14 | describe ActiveMocker::HasMany do 15 | it_behaves_like "HasMany" 16 | it_behaves_like "Queriable", -> (*args) { described_class.new(args.flatten) } 17 | end 18 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/hash_process_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/hash_process" 4 | 5 | describe ActiveMocker::HashProcess do 6 | it do 7 | subject = described_class.new({ id: 1 }, ->(val) { val * 2 }) 8 | expect(subject[:id]).to eq 2 9 | end 10 | 11 | it "merge" do 12 | hash1 = described_class.new({ id: 1 }, ->(val) { val }) 13 | hash2 = described_class.new({ value: 2 }, ->(val) { val }) 14 | subject = hash1.merge(hash2) 15 | expect(subject.hash).to eq(id: 1, value: 2) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/records_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock/records" 4 | require "active_mocker/mock/exceptions" 5 | require "active_support/hash_with_indifferent_access" 6 | require "active_support/core_ext/object/try" 7 | 8 | describe ActiveMocker::Records do 9 | subject { described_class.new } 10 | 11 | let(:record) { RecordBase.new } 12 | 13 | before do 14 | class RecordBase 15 | attr_accessor :id 16 | 17 | def inspect 18 | { id: id } 19 | end 20 | end 21 | end 22 | 23 | describe '#insert' do 24 | it "adds to records" do 25 | expect(subject.insert(record).to_a).to include(record) 26 | end 27 | 28 | it "gets next id" do 29 | subject.insert(record) 30 | expect(record.id).to eq 1 31 | end 32 | 33 | it "validate unique id" do 34 | subject.insert(record) 35 | new_record = RecordBase.new 36 | new_record.id = 1 37 | expect { subject.insert(new_record) }.to raise_exception(ActiveMocker::IdError, "Duplicate ID found for record {:id=>1}") 38 | end 39 | 40 | context 'id#to_i called' do 41 | it "validate string" do 42 | new_record = RecordBase.new 43 | new_record.id = "aa" 44 | subject.insert(new_record) 45 | expect(new_record.id).to eq(0) 46 | end 47 | 48 | it "validate float" do 49 | new_record = RecordBase.new 50 | new_record.id = 1.1 51 | subject.insert(new_record) 52 | expect(new_record.id).to eq(1) 53 | end 54 | end 55 | end 56 | 57 | describe '#delete' do 58 | before do 59 | subject.insert(record) 60 | subject.delete(record) 61 | end 62 | 63 | it "deletes from record array" do 64 | expect(subject.to_a).to eq [] 65 | end 66 | 67 | it "raises if record is not in array" do 68 | expect { described_class.new.delete(record) }.to raise_error(ActiveMocker::RecordNotFound, "Record has not been created.") 69 | end 70 | end 71 | 72 | describe '#existis?' do 73 | it "returns true if has record" do 74 | subject.insert(record) 75 | expect(subject.exists?(record)).to eq true 76 | end 77 | 78 | it "returns false if doesn't have record" do 79 | expect(subject.exists?(record)).to eq false 80 | end 81 | end 82 | 83 | describe '#new_record?' do 84 | it "returns false if has record" do 85 | subject.insert(record) 86 | expect(subject.new_record?(record)).to eq false 87 | end 88 | 89 | it "returns true if doesn't have record" do 90 | expect(subject.new_record?(record)).to eq true 91 | end 92 | end 93 | 94 | describe '#persisted?' do 95 | it "returns true if has record" do 96 | subject.insert(record) 97 | expect(subject.persisted?(record.id)).to eq true 98 | end 99 | 100 | it "returns true if doesn't have record" do 101 | expect(subject.persisted?(record.id)).to eq false 102 | end 103 | end 104 | 105 | describe '#reset' do 106 | it "clears records array and record_index hash" do 107 | subject.insert(record) 108 | subject.reset 109 | expect(subject.send(:records)).to eq([]) 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/mock/relation_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/mock" 4 | require "ostruct" 5 | require_relative "has_many_shared_example" 6 | require_relative "queriable_shared_example" 7 | 8 | describe ActiveMocker::Relation do 9 | it_behaves_like "Queriable", -> (*args) { described_class.new(args.flatten) } 10 | end 11 | -------------------------------------------------------------------------------- /spec/lib/active_mocker/template_creator_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "spec/support/strip_heredoc" 4 | require "active_mocker/template_creator" 5 | require "active_record_schema_scrapper/attribute" 6 | require "active_record_schema_scrapper/attributes" 7 | require "tempfile" 8 | 9 | describe ActiveMocker::TemplateCreator do 10 | using StripHeredoc 11 | 12 | describe "render" do 13 | it "return a file" do 14 | expect(described_class.new(erb_template: double("file", read: "", path: ""), binding: {}.send(:binding)).render.class).to eq(Tempfile) 15 | end 16 | 17 | it "takes an output file to write to" do 18 | file_out = Tempfile.new("fileout") 19 | described_class.new(erb_template: double("file", read: "hello", path: ""), 20 | binding: {}.send(:binding), 21 | file_out: file_out).render.class 22 | file_out.rewind 23 | expect(file_out.read).to eq("hello") 24 | end 25 | 26 | it "given template it will fulfill it based on template model" do 27 | class TestModel 28 | def model_name 29 | :ModelName 30 | end 31 | 32 | def get_binding 33 | binding 34 | end 35 | end 36 | template = Tempfile.new("Template") 37 | template.write <<-ERB 38 | class <%= model_name %> 39 | 40 | end 41 | ERB 42 | template.rewind 43 | result = described_class.new(erb_template: template, 44 | binding: TestModel.new.get_binding).render 45 | result.rewind 46 | expect(result.read).to eq(<<-RUBY) 47 | class ModelName 48 | end 49 | RUBY 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/lib/model_nested.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Api 3 | class ModelNested < ActiveRecord::Base 4 | MY_CONSTANT_VALUE = 3 5 | module FooBar 6 | end 7 | 8 | # include FooBar 9 | # extend Baz 10 | include PostMethods 11 | # include ModelCore::PlanService::Dah 12 | 13 | belongs_to :company, class_name: "PlanServiceCategory", foreign_key: "category_id" 14 | belongs_to :person, through: "customer" 15 | has_many :users 16 | has_one :account 17 | has_and_belongs_to_many :disclosures 18 | devise :database_authenticatable, :registerable, 19 | :recoverable, :rememberable, :trackable, :validatable 20 | 21 | def self.duper(_value, *_args) 22 | end 23 | 24 | scope :named, ->(name, value = nil, options = {}) {} 25 | scope :other_named, -> {} 26 | 27 | def foo(foobar, value) 28 | end 29 | 30 | def self.foo 31 | end 32 | 33 | def superman 34 | end 35 | 36 | def self.bang! 37 | end 38 | 39 | private 40 | 41 | def bar 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/lib/models/model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # ActiveMocker.safe_methods :superman, scopes: [:named], instance_methods: [:foo], class_methods: [:bang!, :foo] 3 | class Model < ActiveRecord::Base 4 | MY_CONSTANT_VALUE = 3 5 | MY_OBJECT = Object.new 6 | module FooBar 7 | end 8 | 9 | # include FooBar 10 | # extend Baz 11 | include PostMethods 12 | # include ModelCore::PlanService::Dah 13 | 14 | belongs_to :company, class_name: "PlanServiceCategory", foreign_key: "category_id" 15 | belongs_to :person, through: "customer" 16 | has_many :users 17 | has_one :account 18 | has_and_belongs_to_many :disclosures 19 | devise :database_authenticatable, :registerable, 20 | :recoverable, :rememberable, :trackable, :validatable 21 | 22 | def self.duper(value, *args) 23 | end 24 | 25 | scope :named, ->(name, value = nil, options = {}) { 2 + 2} 26 | scope :other_named, -> { 1 + 1} 27 | alias_attribute :full_name, :name 28 | def foo(foobar, value) 29 | end 30 | 31 | class << self 32 | def foo 33 | :buz 34 | end 35 | end 36 | 37 | def superman 38 | __method__ 39 | end 40 | 41 | def self.bang! 42 | :boom! 43 | end 44 | 45 | private 46 | 47 | def bar 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/lib/models/non_active_record_model.rb: -------------------------------------------------------------------------------- 1 | class NonActiveRecordModel 2 | end 3 | -------------------------------------------------------------------------------- /spec/lib/models/some_namespace/some_module.rb: -------------------------------------------------------------------------------- 1 | module SomeNamespace 2 | module SomeModule 3 | def some_method 4 | "some return value" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/lib/person.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class Person < ActiveRecord::Base 3 | belongs_to :zip_code 4 | 5 | def full_name 6 | "#{first_name} #{last_name}" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/lib/post_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module PostMethods 3 | def sample_method 4 | end 5 | 6 | def content 7 | "from PostMethods" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rspec" 3 | $LOAD_PATH.unshift File.join(File.expand_path("../../", __FILE__)) 4 | $LOAD_PATH.unshift File.join(File.expand_path("../../", "lib")) 5 | -------------------------------------------------------------------------------- /spec/support/strip_heredoc.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module StripHeredoc 3 | refine String do 4 | def strip_heredoc 5 | indent = scan(/^[ \t]*(?=\S)/).min.size || 0 6 | gsub(/^[ \t]{#{indent}}/, "") 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/unit_logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "logger" 3 | class UnitLogger 4 | def self.method_missing(meth, *args, &block) 5 | return unit.send(meth, *args, &block) unless unit.nil? 6 | return Rails.logger.send(meth, *args, &block) if defined? Rails 7 | end 8 | 9 | def self.unit 10 | return @logger unless @logger.nil? 11 | FileUtils.mkdir_p "log" unless File.directory? "log" 12 | File.open("log/test.log", "w").close unless File.exist? "log/test.log" 13 | @logger = ::Logger.new("log/test.log") 14 | @logger.formatter = proc do |_severity, _datetime, _progname, msg| 15 | msg 16 | end 17 | @logger.level = ::Logger::DEBUG 18 | @logger 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /tasks/integration.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | desc "run integration specs" 3 | task :integration do 4 | Dir.chdir("test_rails_app") do 5 | root = File.expand_path("../../", __FILE__) 6 | gemfiles, error_verbosity = if ENV["TRAVIS"] 7 | [[ENV["BUNDLE_GEMFILE"]], "1"] 8 | else 9 | [Dir[Pathname(File.join(root, "test_rails_app/gemfiles/*.gemfile")).expand_path], 0] 10 | end 11 | Bundler.with_clean_env do 12 | gemfiles.each do |gemfile| 13 | Pathname(gemfile).basename.to_s =~ /rails_(\d\.\d).*/ 14 | rails_version = $1 15 | mock_dir = File.expand_path(File.join(root, "test_rails_app/spec/mocks", rails_version)) 16 | sh "RAILS_VERSION=#{rails_version} MOCK_DIR=#{mock_dir} MUTE_PROGRESS_BAR=true ERROR_VERBOSITY=#{error_verbosity} BUNDLE_GEMFILE=#{gemfile} bundle exec rake active_mocker:build" 17 | sh "RAILS_VERSION=#{rails_version} BUNDLE_GEMFILE=#{gemfile} bundle exec rspec" 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /tasks/setup.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | desc "setup" 3 | task :setup do 4 | unless ENV["TRAVIS"] 5 | Bundler.with_clean_env do 6 | rails_test_gemfile = File.expand_path(File.dirname(__FILE__) + "/../test_rails_app/Gemfile") 7 | sh "BUNDLE_GEMFILE=#{rails_test_gemfile} bundle install --local 2>&1 >/dev/null" do |ok, _res| 8 | sh "BUNDLE_GEMFILE=#{rails_test_gemfile} bundle install" unless ok 9 | end 10 | Dir.chdir("test_rails_app") do 11 | sh "appraisal bundle install" 12 | end 13 | end 14 | end 15 | Dir.chdir("test_rails_app") do 16 | sh "rake db:setup" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /tasks/unit.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | desc "Run unit specs" 4 | task :unit do 5 | sh "bundle exec rspec" 6 | end 7 | -------------------------------------------------------------------------------- /test_rails_app/.secret: -------------------------------------------------------------------------------- 1 | f189df0a71311525020854546e98bafd7f46ef622edaa129c78fabfdeabf6972ab027e9a3d4acee4204b97adbefb32c609216a25bfcd145d7dda29cdd8049618 -------------------------------------------------------------------------------- /test_rails_app/Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails-4.2" do 2 | gem "rails", "~> 4.2.8" 3 | gem "rspec", "~> 3.4" 4 | gem "rspec-rails", "~>3.4" 5 | end 6 | 7 | appraise "rails-5.2" do 8 | gem "rails", "~> 5.2.1" 9 | gem "rspec", "3.7.0" 10 | gem "rspec-rails", "3.7.0" 11 | end 12 | 13 | appraise "rails-6.0" do 14 | gem 'sqlite3', '~> 1.4' 15 | gem "rails", "~> 6.0.0" 16 | gem "actionpack", "~> 6.0.0" 17 | gem "rspec", "3.8.0" 18 | gem "rspec-rails", "4.0.0.beta2" 19 | end 20 | -------------------------------------------------------------------------------- /test_rails_app/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | 4 | gem "rails", "~>4.2" 5 | gem "appraisal" 6 | 7 | gem "capybara", "~>3.15.1" 8 | gem "rspec", ">= 3.4" 9 | gem "sqlite3", "~>1.3.13" 10 | gem "active_mocker", path: "../" 11 | gem "omniauth-identity", "1.1.1" 12 | -------------------------------------------------------------------------------- /test_rails_app/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Michael Hartl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /test_rails_app/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path("../config/application", __FILE__) 6 | 7 | SampleApp::Application.load_tasks 8 | -------------------------------------------------------------------------------- /test_rails_app/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/test_rails_app/app/models/.keep -------------------------------------------------------------------------------- /test_rails_app/app/models/account.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # # ActiveMocker.all_methods_safe 3 | class Account < ActiveRecord::Base 4 | belongs_to :user 5 | 6 | def safe 7 | :hello 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test_rails_app/app/models/api/customer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Api 3 | class Customer < ActiveRecord::Base 4 | has_many :microposts, -> { order("created_at DESC") } 5 | 6 | def User.new_remember_token 7 | SecureRandom.urlsafe_base64 8 | end 9 | 10 | def User.digest(token) 11 | Digest::SHA1.hexdigest(token.to_s) 12 | end 13 | 14 | def feed 15 | Micropost.from_users_followed_by(self) 16 | end 17 | 18 | def following?(other_user) 19 | relationships.find_by(followed_id: other_user.id) 20 | end 21 | 22 | def follow!(other_user) 23 | relationships.create!(followed_id: other_user.id) 24 | end 25 | 26 | def unfollow!(other_user) 27 | relationships.find_by(followed_id: other_user.id).destroy 28 | end 29 | 30 | def key_arg_reg(key:) 31 | end 32 | 33 | def key_arg_opt(key: nil) 34 | end 35 | 36 | def key_arg_rest(**key_rest) 37 | end 38 | 39 | def arg_rest(*key_rest) 40 | end 41 | 42 | private 43 | 44 | def create_remember_token 45 | self.remember_token = User.digest(User.new_remember_token) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /test_rails_app/app/models/child_model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # ActiveMocker.all_methods_safe 3 | class ChildModel < User 4 | has_many :accounts 5 | 6 | scope :by_credits, -> (credits) { where(credits: credits) } 7 | scope :i_take_a_block, -> () { where(credits: credits) } 8 | 9 | def child_method 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test_rails_app/app/models/has_no_parent.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class HasNoParent 3 | end 4 | -------------------------------------------------------------------------------- /test_rails_app/app/models/has_no_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class HasNoTable < ActiveRecord::Base 3 | self.abstract_class = true 4 | end 5 | -------------------------------------------------------------------------------- /test_rails_app/app/models/identity.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class Identity < OmniAuth::Identity::Models::ActiveRecord 3 | end 4 | -------------------------------------------------------------------------------- /test_rails_app/app/models/micropost.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "#{Rails.root}/lib/post_methods" 3 | 4 | class Micropost < ActiveRecord::Base 5 | belongs_to :user 6 | default_scope -> { order("created_at DESC") } 7 | MAGIC_ID_NUMBER = 90 8 | MAGIC_ID_STRING = "F-1" 9 | 10 | include PostMethods 11 | extend PostMethods 12 | include Core 13 | 14 | module DoNotIncludeInMock 15 | def sample_method 16 | end 17 | end 18 | include DoNotIncludeInMock 19 | # self.primary_key = :lol 20 | # self.table_name = :posts 21 | # Returns microposts from the users being followed by the given user. 22 | def self.from_users_followed_by(user = nil) 23 | followed_user_ids = "SELECT followed_id FROM relationships 24 | WHERE follower_id = :user_id" 25 | where("user_id IN (#{followed_user_ids}) OR user_id = :user_id", 26 | user_id: user.id) 27 | end 28 | 29 | def display_name 30 | end 31 | 32 | def post_id 33 | id 34 | end 35 | 36 | def i_take_block(&block) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /test_rails_app/app/models/micropost/core.rb: -------------------------------------------------------------------------------- 1 | class Micropost 2 | module Core 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test_rails_app/app/models/relationship.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class Relationship < ActiveRecord::Base 3 | belongs_to :follower, class_name: "User" 4 | belongs_to :followed, class_name: "User" 5 | validates :follower_id, presence: true 6 | validates :followed_id, presence: true 7 | end 8 | -------------------------------------------------------------------------------- /test_rails_app/app/models/user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # ActiveMocker.safe_methods :initialize, :safe_method1, :safe_method2, scopes: [ :by_name ], class_methods: [:digest] 3 | class User < ActiveRecord::Base 4 | has_many :microposts, -> { order("created_at DESC") } 5 | has_many :relationships, foreign_key: "follower_id", dependent: :destroy 6 | has_many :followed_users, through: :relationships, source: :followed 7 | has_many :reverse_relationships, foreign_key: "followed_id", 8 | class_name: "Relationship", 9 | dependent: :destroy 10 | has_many :followers, through: :reverse_relationships, source: :follower 11 | has_one :account 12 | scope :find_by_name, -> (name) { where(name: name) } 13 | scope :by_name, -> (name) { where(name: name) } 14 | scope :no_arg_scope, -> { where(name: "name") } 15 | 16 | alias_attribute :first_and_last_name, :name 17 | enum status: { active: 0, archived: 1 } 18 | def self.new_remember_token 19 | SecureRandom.urlsafe_base64 20 | end 21 | 22 | def self.digest(token) 23 | Digest::SHA1.hexdigest(token.to_s) 24 | end 25 | 26 | def feed 27 | Micropost.from_users_followed_by(self) 28 | end 29 | 30 | def following?(other_user) 31 | relationships.find_by(followed_id: other_user.id) 32 | end 33 | 34 | def follow!(other_user) 35 | relationships.create!(followed_id: other_user.id) 36 | end 37 | 38 | def unfollow!(other_user) 39 | relationships.find_by(followed_id: other_user.id).destroy 40 | end 41 | 42 | def key_arg_reg(key:) 43 | end 44 | 45 | def key_arg_opt(key:nil) 46 | end 47 | 48 | def initialize(*args) 49 | @test_that_this_was_run = true 50 | super 51 | end 52 | 53 | def safe_method1 54 | 1+1 55 | end 56 | 57 | def safe_method2 58 | 2+2 59 | end 60 | 61 | private 62 | 63 | def create_remember_token 64 | self.remember_token = User.digest(User.new_remember_token) 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /test_rails_app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) 4 | load Gem.bin_path("bundler", "bundle") 5 | -------------------------------------------------------------------------------- /test_rails_app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | APP_PATH = File.expand_path("../../config/application", __FILE__) 4 | require_relative "../config/boot" 5 | require "rails/commands" 6 | -------------------------------------------------------------------------------- /test_rails_app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | require_relative "../config/boot" 4 | require "rake" 5 | Rake.application.run 6 | -------------------------------------------------------------------------------- /test_rails_app/bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # This file was generated by Bundler. 5 | # 6 | # The application 'rspec' is installed as part of a gem, and 7 | # this file is here to facilitate running it. 8 | # 9 | 10 | require "pathname" 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 12 | Pathname.new(__FILE__).realpath) 13 | 14 | require "rubygems" 15 | require "bundler/setup" 16 | 17 | load Gem.bin_path("rspec-core", "rspec") 18 | -------------------------------------------------------------------------------- /test_rails_app/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file is used by Rack-based servers to start the application. 3 | 4 | require ::File.expand_path("../config/environment", __FILE__) 5 | run SampleApp::Application 6 | -------------------------------------------------------------------------------- /test_rails_app/config/application.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../boot", __FILE__) 3 | # Pick the frameworks you want: 4 | require "active_record/railtie" 5 | 6 | Bundler.require(*Rails.groups) 7 | require 'rails/all' 8 | # require "rails/test_unit/railtie" 9 | 10 | # Assets should be precompiled for production (so we don't need the gems loaded then) 11 | # Bundler.require(*Rails.groups(assets: %w(development test))) 12 | 13 | module SampleApp 14 | class Application < Rails::Application 15 | # Settings in config/environments/* take precedence over those specified here. 16 | # Application configuration should go into files in config/initializers 17 | # -- all .rb files in that directory are automatically loaded. 18 | 19 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 20 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 21 | # config.time_zone = 'Central Time (US & Canada)' 22 | 23 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 24 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 25 | # config.i18n.default_locale = :de 26 | # I18n.enforce_available_locales = true 27 | I18n.enforce_available_locales = true 28 | config.autoload_paths << Rails.root.join("lib") 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test_rails_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Set up gems listed in the Gemfile. 3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) 4 | 5 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) 6 | -------------------------------------------------------------------------------- /test_rails_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | encoding: utf8 18 | pool: 5 19 | timeout: 5000 20 | database: db/test.sqlite3 21 | verbosity: quiet 22 | 23 | production: 24 | adapter: sqlite3 25 | database: db/production.sqlite3 26 | pool: 5 27 | timeout: 5000 -------------------------------------------------------------------------------- /test_rails_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Load the rails application. 3 | require File.expand_path("../application", __FILE__) 4 | 5 | # Initialize the rails application. 6 | SampleApp::Application.initialize! 7 | -------------------------------------------------------------------------------- /test_rails_app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | SampleApp::Application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # In the development environment your application's code is reloaded on 6 | # every request. This slows down response time but is perfect for development 7 | # since you don't have to restart the web server when you make code changes. 8 | config.cache_classes = false 9 | 10 | # Do not eager load code on boot. 11 | config.eager_load = false 12 | 13 | # Show full error reports and disable caching. 14 | config.consider_all_requests_local = true 15 | 16 | # Don't care if the mailer can't send. 17 | 18 | # Print deprecation notices to the Rails logger. 19 | config.active_support.deprecation = :log 20 | 21 | # Raise an error on page load if there are pending migrations 22 | config.active_record.migration_error = :page_load 23 | 24 | # Debug mode disables concatenation and preprocessing of assets. 25 | end 26 | -------------------------------------------------------------------------------- /test_rails_app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | SampleApp::Application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # Code is not reloaded between requests. 6 | config.cache_classes = true 7 | 8 | # Eager load code on boot. This eager loads most of Rails and 9 | # your application in memory, allowing both thread web servers 10 | # and those relying on copy on write to perform better. 11 | # Rake tasks automatically ignore this option for performance. 12 | config.eager_load = true 13 | 14 | # Full error reports are disabled and caching is turned on. 15 | config.consider_all_requests_local = false 16 | config.action_controller.perform_caching = true 17 | 18 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 19 | # Add `rack-cache` to your Gemfile before enabling this. 20 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Compress JavaScripts and CSS. 24 | config.assets.js_compressor = :uglifier 25 | # config.assets.css_compressor = :sass 26 | 27 | # Whether to fallback to assets pipeline if a precompiled asset is missed. 28 | config.assets.compile = false 29 | 30 | # Generate digests for assets URLs. 31 | config.assets.digest = true 32 | 33 | # Version of your assets, change this if you want to expire all your assets. 34 | config.assets.version = "1.0" 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 38 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 39 | 40 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 41 | config.force_ssl = true 42 | 43 | # Set to :debug to see everything in the log. 44 | config.log_level = :info 45 | 46 | # Prepend all log lines with the following tags. 47 | # config.log_tags = [ :subdomain, :uuid ] 48 | 49 | # Use a different logger for distributed setups. 50 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 51 | 52 | # Use a different cache store in production. 53 | # config.cache_store = :mem_cache_store 54 | 55 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 56 | # config.action_controller.asset_host = "http://assets.example.com" 57 | 58 | # Precompile additional assets. 59 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 60 | # config.assets.precompile += %w( search.js ) 61 | 62 | # Ignore bad email addresses and do not raise email delivery errors. 63 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 64 | # config.action_mailer.raise_delivery_errors = false 65 | 66 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 67 | # the I18n.default_locale when a translation can not be found). 68 | config.i18n.fallbacks = true 69 | 70 | # Send deprecation notices to registered listeners. 71 | config.active_support.deprecation = :notify 72 | 73 | # Disable automatic flushing of the log to improve performance. 74 | # config.autoflush_log = false 75 | 76 | # Use default logging formatter so that PID and timestamp are not suppressed. 77 | config.log_formatter = ::Logger::Formatter.new 78 | end 79 | -------------------------------------------------------------------------------- /test_rails_app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | SampleApp::Application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # The test environment is used exclusively to run your application's 6 | # test suite. You never need to work with it otherwise. Remember that 7 | # your test database is "scratch space" for the test suite and is wiped 8 | # and recreated between test runs. Don't rely on the data there! 9 | config.cache_classes = true 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure static asset server for tests with Cache-Control for performance. 17 | # Show full error reports and disable caching. 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates. 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment. 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | 31 | # Print deprecation notices to the stderr. 32 | config.active_support.deprecation = :stderr 33 | 34 | # Speed up tests by lowering bcrypt's cost function. 35 | ActiveModel::SecurePassword.min_cost = true 36 | end 37 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 6 | 7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 8 | # Rails.backtrace_cleaner.remove_silencers! 9 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Configure sensitive parameters which will be filtered from the log file. 5 | Rails.application.config.filter_parameters += [:password] 6 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new inflection rules using the following format. Inflections 5 | # are locale specific, and you may define rules for as many different 6 | # locales as you wish. All of these examples are active by default: 7 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 8 | # inflect.plural /^(ox)$/i, '\1en' 9 | # inflect.singular /^(ox)en/i, '\1' 10 | # inflect.irregular 'person', 'people' 11 | # inflect.uncountable %w( fish sheep ) 12 | # end 13 | 14 | # These inflection rules are supported but not enabled by default: 15 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 16 | # inflect.acronym 'RESTful' 17 | # end 18 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new mime types for use in respond_to blocks: 5 | # Mime::Type.register "text/richtext", :rtf 6 | # Mime::Type.register_alias "text/html", :iphone 7 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Make sure your secret_key_base is kept private 5 | # if you're sharing your code publicly, such as by adding 6 | # .secret to your .gitignore file. 7 | 8 | require "securerandom" 9 | 10 | def secure_token 11 | token_file = Rails.root.join(".secret") 12 | if File.exist?(token_file) 13 | # Use the existing token. 14 | File.read(token_file).chomp 15 | else 16 | # Generate a new token and store it in token_file. 17 | token = SecureRandom.hex(64) 18 | File.write(token_file, token) 19 | token 20 | end 21 | end 22 | 23 | SampleApp::Application.config.secret_key_base = secure_token 24 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | SampleApp::Application.config.session_store :cookie_store, key: "_sample_app_session" 5 | -------------------------------------------------------------------------------- /test_rails_app/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # This file contains settings for ActionController::ParamsWrapper which 5 | # is enabled by default. 6 | 7 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 8 | ActiveSupport.on_load(:action_controller) do 9 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 10 | end 11 | 12 | # To enable root element in JSON for ActiveRecord objects. 13 | # ActiveSupport.on_load(:active_record) do 14 | # self.include_root_in_json = true 15 | # end 16 | -------------------------------------------------------------------------------- /test_rails_app/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /test_rails_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | SampleApp::Application.routes.draw do 3 | resources :users do 4 | member do 5 | get :following, :followers 6 | end 7 | end 8 | resources :sessions, only: [:new, :create, :destroy] 9 | resources :microposts, only: [:create, :destroy] 10 | resources :relationships, only: [:create, :destroy] 11 | root to: 'static_pages#home' 12 | match "/signup", to: 'users#new', via: "get" 13 | match "/signin", to: 'sessions#new', via: "get" 14 | match "/signout", to: 'sessions#destroy', via: "delete" 15 | match "/help", to: 'static_pages#help', via: "get" 16 | match "/about", to: 'static_pages#about', via: "get" 17 | match "/contact", to: 'static_pages#contact', via: "get" 18 | end 19 | -------------------------------------------------------------------------------- /test_rails_app/db/migrate/20160621215939_create_products.rb: -------------------------------------------------------------------------------- 1 | class CreateProducts < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :products do |t| 4 | t.string :name 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test_rails_app/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20160621215939) do 15 | 16 | create_table "accounts", force: :cascade do |t| 17 | t.integer "user_id" 18 | t.decimal "balance" 19 | end 20 | 21 | create_table "customers", force: :cascade do |t| 22 | t.string "name" 23 | t.string "email", default: "" 24 | t.decimal "credits", precision: 19, scale: 6, default: -1.0 25 | t.datetime "created_at" 26 | t.datetime "updated_at" 27 | t.string "password_digest" 28 | t.boolean "remember_token", default: true 29 | t.boolean "admin", default: false 30 | end 31 | 32 | create_table "identities", force: :cascade do |t| 33 | t.string "name" 34 | t.string "email", default: "n/a" 35 | t.decimal "credits", precision: 19, scale: 6, default: -2.0 36 | t.datetime "created_at" 37 | t.datetime "updated_at" 38 | t.string "password_digest" 39 | t.boolean "remember_token", default: true 40 | t.boolean "admin", default: false 41 | end 42 | 43 | create_table "microposts", force: :cascade do |t| 44 | t.string "content" 45 | t.integer "user_id" 46 | t.integer "up_votes" 47 | t.datetime "created_at" 48 | t.datetime "updated_at" 49 | t.index ["user_id", "created_at"], name: "index_microposts_on_user_id_and_created_at" 50 | end 51 | 52 | create_table "products", force: :cascade do |t| 53 | t.string "name" 54 | end 55 | 56 | create_table "relationships", force: :cascade do |t| 57 | t.integer "follower_id" 58 | t.integer "followed_id" 59 | t.datetime "created_at" 60 | t.datetime "updated_at" 61 | t.index ["followed_id"], name: "index_relationships_on_followed_id" 62 | t.index ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true 63 | t.index ["follower_id"], name: "index_relationships_on_follower_id" 64 | end 65 | 66 | create_table "users", force: :cascade do |t| 67 | t.string "name" 68 | t.string "email", default: "" 69 | t.decimal "credits", precision: 19, scale: 6, default: -1.0 70 | t.datetime "requested_at", default: DateTime.parse("3rd Feb 2001 04:05:06+03:30") 71 | t.datetime "created_at" 72 | t.datetime "updated_at" 73 | t.string "password_digest" 74 | t.boolean "remember_token", default: true 75 | t.boolean "admin", default: false 76 | t.index ["email"], name: "index_users_on_email", unique: true 77 | t.index ["remember_token"], name: "index_users_on_remember_token" 78 | t.integer :status, default: 0 79 | end 80 | 81 | end 82 | -------------------------------------------------------------------------------- /test_rails_app/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file should contain all the record creation needed to seed the database with its default values. 3 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 4 | # 5 | # Examples: 6 | # 7 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 8 | # Mayor.create(name: 'Emanuel', city: cities.first) 9 | -------------------------------------------------------------------------------- /test_rails_app/gemfiles/rails_4.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rails", "~> 4.2.8" 6 | gem "appraisal" 7 | gem "capybara", "~>3.15.1" 8 | gem "rspec", "~> 3.4" 9 | gem "sqlite3", "~>1.3.13" 10 | gem "active_mocker", path: "../../" 11 | gem "omniauth-identity", "1.1.1" 12 | gem "rspec-rails", "~>3.4" 13 | -------------------------------------------------------------------------------- /test_rails_app/gemfiles/rails_5.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rails", "~> 5.2.1" 6 | gem "appraisal" 7 | gem "capybara", "~>3.15.1" 8 | gem "rspec", "3.7.0" 9 | gem "sqlite3", "~>1.3.13" 10 | gem "active_mocker", path: "../../" 11 | gem "omniauth-identity", "1.1.1" 12 | gem "rspec-rails", "3.7.0" 13 | -------------------------------------------------------------------------------- /test_rails_app/gemfiles/rails_6.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rails", "~> 6.0.0" 6 | gem "appraisal" 7 | gem "capybara", "~>3.15.1" 8 | gem "rspec", "3.8.0" 9 | gem "sqlite3", "~> 1.4" 10 | gem "active_mocker", path: "../../" 11 | gem "omniauth-identity", "1.1.1" 12 | gem "actionpack", "~> 6.0.0" 13 | gem "rspec-rails", "4.0.0.beta2" 14 | -------------------------------------------------------------------------------- /test_rails_app/lib/post_methods.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module PostMethods 3 | def sample_method 4 | end 5 | 6 | def content 7 | "from PostMethods" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test_rails_app/lib/unit_logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "logger" 3 | class UnitLogger 4 | def self.method_missing(meth, *args, &block) 5 | return Rails.logger.send(meth, *args, &block) if defined? Rails 6 | unit.send(meth, *args, &block) 7 | end 8 | 9 | def self.unit 10 | return @logger unless @logger.nil? 11 | @logger = Logger.new(STDOUT) 12 | @logger.formatter = proc do |_severity, _datetime, _progname, msg| 13 | msg 14 | end 15 | @logger.level = Logger::DEBUG 16 | @logger 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test_rails_app/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeisler/active_mocker/8c795c9ee8a8ef1e94d81fbcb0e44ab64e672928/test_rails_app/log/.keep -------------------------------------------------------------------------------- /test_rails_app/spec/account_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require_mock "user_mock" 4 | require_mock "account_mock" 5 | 6 | describe AccountMock do 7 | it "has_one user" do 8 | user = UserMock.create 9 | account = described_class.new(user: user) 10 | expect(user.account).to eq account 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test_rails_app/spec/api/customer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require_mock "api/customer_mock" 4 | 5 | RSpec.describe Api::CustomerMock do 6 | describe "::mocked_class" do 7 | it "returns the class name with the namespace" do 8 | expect(described_class.send(:mocked_class)).to eq "Api::Customer" 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test_rails_app/spec/child_model_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require "active_mocker/rspec_helper" 4 | require_mock "user_mock" 5 | require_mock "child_model_mock" 6 | 7 | describe ChildModel do 8 | it "column_names" do 9 | expect(ChildModelMock.column_names).to eq ChildModel.column_names 10 | end 11 | 12 | context "mutatable objects " do 13 | it "email" do 14 | ChildModelMock.new.email << "@" 15 | expect(ChildModelMock.new.email).to eq("") 16 | end 17 | end 18 | 19 | it "table_name" do 20 | expect(ChildModelMock.table_name).to eq ChildModel.table_name 21 | end 22 | 23 | it "reflections" do 24 | expect(ChildModelMock.reflections).to eq UserMock.reflections.merge("accounts" => nil) 25 | end 26 | 27 | it "has parent class of UserMock" do 28 | expect(ChildModelMock.superclass.name).to eq "UserMock" 29 | end 30 | 31 | it "has its methods" do 32 | expect(ChildModelMock.public_instance_methods.sort - Object.public_instance_methods).to eq ([:accounts, :accounts=, :child_method] + ChildModelMock.public_instance_methods.sort - Object.public_instance_methods).uniq.sort 33 | end 34 | 35 | it "has a parent method" do 36 | expect(ChildModelMock.instance_methods).to include(:id, :id=, :name, :name=, :email, :email=, :credits, :credits=, :created_at, :created_at=, :updated_at, :updated_at=, :password_digest, :password_digest=, :remember_token, :remember_token=, :admin, :admin=, :account, :account=, :build_account, :create_account, :create_account!, :microposts, :microposts=, :relationships, :relationships=, :followed_users, :followed_users=, :reverse_relationships, :reverse_relationships=, :followers, :followers=, :child_method, :feed, :following?, :follow!, :unfollow!) 37 | end 38 | 39 | it "scoped methods" do 40 | expect(ChildModelMock::Scopes.instance_methods).to include(*UserMock::Scopes.instance_methods, *:by_credits) 41 | end 42 | 43 | it "stubbed parent methods are stubbed on child" do 44 | allow_any_instance_of(UserMock).to receive(:feed) { "Feed!" } 45 | expect(ChildModelMock.new.feed).to eq "Feed!" 46 | end 47 | 48 | context "auto stubbing", active_mocker: true do 49 | it "is a mock" do 50 | expect(ChildModel.ancestors).to include(ActiveMocker::Base) 51 | end 52 | 53 | it "can be searched for" do 54 | expect(active_mocker.find("ChildModel").ancestors).to include(ActiveMocker::Base) 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /test_rails_app/spec/clear_after_all_example_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/rspec_helper" 4 | require "lib/post_methods" 5 | require_mock "micropost_mock" 6 | require_mock "user_mock" 7 | 8 | describe "1) State Not Shared between outer examples", active_mocker: true do 9 | context "state in one example will not leak to another" do 10 | it "make a record" do 11 | MicropostMock.create(content: "from 1) false") 12 | end 13 | end 14 | end 15 | 16 | describe "2) State Not Shared between outer examples", active_mocker: true do 17 | context "state in one example will not leak to another" do 18 | it "count records" do 19 | expect(MicropostMock.all.to_a).to eq([]) 20 | expect(MicropostMock.count).to eq 0 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /test_rails_app/spec/const_stub_example_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "active_mocker/rspec_helper" 4 | require "lib/post_methods" 5 | require_mock "micropost_mock" 6 | require_mock "user_mock" 7 | 8 | describe "Another Example", active_mocker: true do 9 | context '#mock_class' do 10 | before do 11 | active_mocker.mocks.find("Micropost").create! 12 | User.create 13 | active_mocker.mocks.except(User).delete_all 14 | end 15 | 16 | after do 17 | active_mocker.mocks.delete_all 18 | end 19 | 20 | it "will create an instance of mock" do 21 | expect(Micropost.count).to eq 0 22 | expect(User.count).to eq 1 23 | end 24 | 25 | it "will create an instance of mock 2" do 26 | expect(Micropost.count).to eq 0 27 | expect(User.count).to eq 1 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test_rails_app/spec/factories.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | FactoryGirl.define do 3 | factory :user do 4 | sequence(:name) { |n| "Person #{n}" } 5 | sequence(:email) { |n| "person_#{n}@example.com" } 6 | password "foobar" 7 | password_confirmation "foobar" 8 | 9 | factory :admin do 10 | admin true 11 | end 12 | end 13 | 14 | factory :micropost do 15 | content "Lorem ipsum" 16 | user 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test_rails_app/spec/features_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "active_mocker/rspec_helper" 3 | require_mock "user_mock" 4 | 5 | describe "ActiveMocker::Features", active_mocker: true do 6 | describe "delete_all_before_example", order: :defined do 7 | context "when enabled" do 8 | before(:all) { active_mocker.features.enable(:delete_all_before_example) } 9 | after(:all) { active_mocker.features.disable(:delete_all_before_example) } 10 | it "test1" do 11 | 10.times do 12 | User.create 13 | end 14 | 15 | expect(User.count).to eq(10) 16 | end 17 | 18 | it "test2" do 19 | User.create 20 | expect(User.count).to eq(1) 21 | end 22 | end 23 | 24 | context "when disabled" do 25 | it "test1" do 26 | 10.times do 27 | User.create 28 | end 29 | 30 | expect(User.count).to eq(10) 31 | end 32 | 33 | it "test2" do 34 | User.create 35 | expect(User.count).to eq(11) 36 | end 37 | end 38 | end 39 | 40 | describe "timestamps" do 41 | context "when enabled" do 42 | before(:all) { active_mocker.features.enable(:timestamps) } 43 | after(:all) { active_mocker.features.disable(:timestamps) } 44 | 45 | it "touches updated_at and created_at" do 46 | record = User.create 47 | expect(record.updated_at).to_not be_nil 48 | expect(record.created_at).to_not be_nil 49 | end 50 | 51 | context "when touch is called" do 52 | it "increments the updated at" do 53 | record = User.create 54 | first_time = record.updated_at 55 | record.touch 56 | expect(record.updated_at > first_time).to eq(true) 57 | end 58 | end 59 | end 60 | 61 | context "when disabled" do 62 | it "touches updated_at and created_at" do 63 | record = User.create 64 | expect(record.updated_at).to be_nil 65 | expect(record.created_at).to be_nil 66 | end 67 | end 68 | end 69 | 70 | describe "stub_active_record_exceptions", active_mocker: true do 71 | it "can load these exceptions" do 72 | ActiveRecord::RecordNotFound 73 | ActiveRecord::RecordNotUnique 74 | ActiveRecord::UnknownAttributeError 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /test_rails_app/spec/has_no_table_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require_mock "has_no_table_mock" 4 | 5 | describe HasNoTableMock do 6 | it "will raise error on initialization" do 7 | expect { described_class.new }.to raise_error("HasNoTableMock is an abstract class and cannot be instantiated.") 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test_rails_app/spec/idenity_mock_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require_mock "identity_mock" 4 | 5 | describe IdentityMock do 6 | it "has base class of Base" do 7 | expect(described_class.superclass).to eq ActiveMocker::Base 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test_rails_app/spec/micropost_mock_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "lib/post_methods" 4 | require_mock "micropost_mock" 5 | require_mock "user_mock" 6 | 7 | describe MicropostMock do 8 | describe "user=" do 9 | it "setting user will assign its foreign key" do 10 | user = UserMock.create! 11 | post = MicropostMock.create(user: user) 12 | expect(post.user_id).to eq user.id 13 | end 14 | end 15 | 16 | describe "::MAGIC_ID_NUMBER" do 17 | it "has constant from model" do 18 | expect(MicropostMock::MAGIC_ID_NUMBER).to eq 90 19 | end 20 | end 21 | 22 | context "included methods" do 23 | it "has methods" do 24 | expect(MicropostMock.new.respond_to?(:sample_method)).to eq true 25 | end 26 | 27 | it "can override attributes" do 28 | post = MicropostMock.new(content: "attribute") 29 | expect(post.content).to eq "from PostMethods" 30 | end 31 | end 32 | 33 | context "extended methods" do 34 | it "has methods" do 35 | expect(MicropostMock.respond_to?(:sample_method)).to eq true 36 | end 37 | end 38 | 39 | describe "::MAGIC_ID_STRING" do 40 | it "has constant from model" do 41 | expect(MicropostMock::MAGIC_ID_STRING).to eq "F-1" 42 | end 43 | end 44 | 45 | describe "::constants" do 46 | it "has constant from model" do 47 | expect(MicropostMock.constants).to include(:MAGIC_ID_NUMBER, :MAGIC_ID_STRING) 48 | end 49 | end 50 | 51 | describe 'has_one#create_attribute' do 52 | let(:post) { MicropostMock.new } 53 | 54 | it "can create off of has_one" do 55 | user = post.create_user 56 | expect(post.user).to eq user 57 | expect(user.persisted?).to eq true 58 | end 59 | end 60 | 61 | describe 'has_one#build_attribute' do 62 | let(:post) { MicropostMock.new } 63 | 64 | it "can create off of has_one" do 65 | user = post.build_user 66 | expect(post.user).to eq user 67 | expect(user.persisted?).to eq false 68 | end 69 | end 70 | 71 | describe "Mocking methods" do 72 | context "mocked from class before new" do 73 | before do 74 | allow_any_instance_of(MicropostMock).to receive(:display_name) do 75 | "Method Mocked at class level" 76 | end 77 | end 78 | 79 | it "when no instance level mocks is set will default to class level" do 80 | expect(MicropostMock.new.display_name).to eq "Method Mocked at class level" 81 | end 82 | 83 | it "instance mocking overrides class mocking" do 84 | post = MicropostMock.new 85 | allow(post).to receive(:display_name) do 86 | "Method Mocked at instance level" 87 | end 88 | expect(post.display_name).to eq "Method Mocked at instance level" 89 | end 90 | end 91 | end 92 | 93 | after(:each) do 94 | ActiveMocker::LoadedMocks.clear_all 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /test_rails_app/spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | ENV["RAILS_ENV"] ||= "test" 3 | require "spec_helper" 4 | require File.expand_path("../../config/environment", __FILE__) 5 | require "rspec/rails" 6 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 7 | 8 | ActiveRecord::Migration.maintain_test_schema! 9 | require "spec_helper" 10 | RSpec.configure do |config| 11 | config.use_transactional_fixtures = true 12 | config.infer_base_class_for_anonymous_controllers = false 13 | end 14 | -------------------------------------------------------------------------------- /test_rails_app/spec/rake_task_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require "rake" 4 | 5 | describe "rake active_mocker:build" do 6 | before { SampleApp::Application.load_tasks } 7 | it "builds the mocks from the model dir" do 8 | expect(File.exist? mock_path).to eq true 9 | expect(File.exist? File.join(mock_path, "user_mock.rb")).to eq true 10 | expect(File.exist? File.join(mock_path, "micropost_mock.rb")).to eq true 11 | expect(File.exist? File.join(mock_path, "relationship_mock.rb")).to eq true 12 | expect(File.exist? File.join(mock_path, "api/customer_mock.rb")).to eq true 13 | expect(File.exist? File.join(mock_path, "nacis_mock.rb")).to eq false 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test_rails_app/spec/relation_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require_mock "user_mock" 4 | require_relative "../../spec/lib/active_mocker/mock/queriable_shared_example" 5 | 6 | describe UserMock do 7 | describe "ActiveMocker::MockRelation" do 8 | it_behaves_like "Queriable", -> (*args) { ActiveMocker::MockRelation.new(UserMock, args.flatten) } 9 | 10 | subject { ActiveMocker::MockRelation.new(UserMock, collection) } 11 | let(:collection) { [UserMock.new, UserMock.new] } 12 | 13 | it "call a private method on class" do 14 | expect(UserMock).to receive(:__new_relation__).with(collection) 15 | subject 16 | end 17 | 18 | it "has the correct count" do 19 | expect(subject.count).to eq 2 20 | end 21 | 22 | it "has scoped methods" do 23 | expect(subject.respond_to?(:find_by_name)).to eq true 24 | expect(subject.respond_to?(:by_name)).to eq true 25 | expect(subject.respond_to?(:no_arg_scope)).to eq true 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /test_rails_app/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rspec" 3 | ENV["RAILS_VERSION"] ||= "4.2" 4 | $LOAD_PATH.unshift File.expand_path("../../", __FILE__) 5 | APP_ROOT = File.expand_path("../../", __FILE__) unless defined? APP_ROOT 6 | 7 | RSpec.configure do |config| 8 | config.order = "random" 9 | 10 | config.expect_with :rspec do |c| 11 | c.syntax = :expect 12 | end 13 | 14 | config.mock_with :rspec do |mocks| 15 | mocks.verify_doubled_constant_names = true 16 | mocks.verify_partial_doubles = true 17 | end 18 | end 19 | 20 | def require_mock(name) 21 | require "#{mock_path}/#{name}" 22 | end 23 | 24 | def mock_path 25 | rails_version = if ENV["RAILS_VERSION"] 26 | ENV["RAILS_VERSION"] 27 | elsif defined? Rails 28 | "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}" 29 | else 30 | "5.2" 31 | end 32 | File.join(APP_ROOT, "spec/mocks/#{rails_version}") 33 | end 34 | -------------------------------------------------------------------------------- /test_rails_app/spec/user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rails_helper" 3 | require_relative "active_record_compatible_api" 4 | 5 | describe User do 6 | it_behaves_like "ActiveRecord", Micropost, Account 7 | end 8 | -------------------------------------------------------------------------------- /test_rails_app/test_rails_4_app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------