diff --git a/.gitignore b/.gitignore index 7c80de9..30817d2 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -.ruby-version -.ruby-gemset *.gem *.rbc .bundle @@ -8,8 +6,11 @@ .rbenv-* .rbx .rbxpkg +.ruby-gemset +.ruby-version .rvmrc .yardoc +_yardoc coverage doc/ Gemfile.lock @@ -21,4 +22,3 @@ tags test/tmp test/version_tmp tmp -_yardoc diff --git a/.rspec b/.rspec new file mode 100755 index 0000000..83e16f8 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100755 index 0000000..6fe558b --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,60 @@ +--- +require: rubocop-rspec +inherit_from: .rubocop_todo.yml + +AllCops: + TargetRubyVersion: 2.2 + DisplayCopNames: true + Exclude: + - 'tmp/**/*' + +Style/MixinGrouping: + Exclude: + - 'spec/**/*.rb' + +Metrics/BlockLength: + CountComments: false # count full line comments? + Exclude: + - '**/*_spec.rb' + +StringLiterals: + EnforcedStyle: single_quotes + Enabled: true + +DotPosition: + EnforcedStyle: leading + Enabled: true + +ClassAndModuleChildren: + EnforcedStyle: nested + Enabled: true + +Documentation: + Enabled: false + +FileName: + Enabled: true + +LineLength: + Max: 120 + Enabled: true + +Style/ExtraSpacing: + Enabled: true + +Lint/LiteralInInterpolation: + AutoCorrect: true + +Style/ModuleFunction: + EnforcedStyle: extend_self # Allows us to have private methods too + +Style/PercentLiteralDelimiters: + # Hound and CodeClimate are currently using an old version of Rubocop with + # different defaults, so we set them explicitly here. + PreferredDelimiters: + default: () + '%i': '[]' + '%I': '[]' + '%r': '{}' + '%w': '[]' + '%W': '[]' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100755 index 0000000..8015a65 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,92 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2017-05-16 15:42:20 +0100 using RuboCop version 0.48.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +Metrics/AbcSize: + Max: 17 + +# Offense count: 1 +Metrics/CyclomaticComplexity: + Max: 7 + +# Offense count: 1 +# Configuration parameters: CountComments. +Metrics/MethodLength: + Max: 13 + +# Offense count: 1 +Metrics/PerceivedComplexity: + Max: 8 + +# Offense count: 1 +RSpec/DescribeMethod: + Exclude: + - 'spec/machinist/exceptions_spec.rb' + +# Offense count: 17 +# Configuration parameters: Max. +RSpec/ExampleLength: + Exclude: + - 'spec/machinist/active_record_spec.rb' + - 'spec/machinist/blueprint_inheritance_spec.rb' + - 'spec/machinist/blueprint_spec.rb' + - 'spec/machinist/machinable_spec.rb' + +# Offense count: 2 +RSpec/IteratedExpectation: + Exclude: + - 'spec/machinist/blueprint_spec.rb' + - 'spec/machinist/machinable_spec.rb' + +# Offense count: 21 +RSpec/MultipleExpectations: + Max: 6 + +# Offense count: 2 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Exclude: + - 'lib/machinist/active_record/blueprint.rb' + - 'lib/machinist/active_record/lathe.rb' + +# Offense count: 1 +# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms. +# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS +Style/FileName: + Exclude: + - 'Appraisals' + +# Offense count: 1 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: format, sprintf, percent +Style/FormatString: + Exclude: + - 'lib/machinist/blueprint.rb' + +# Offense count: 3 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Exclude: + - 'lib/generators/machinist/install/install_generator.rb' + - 'lib/machinist/lathe.rb' + +# Offense count: 1 +Style/MethodMissing: + Exclude: + - 'lib/machinist/lathe.rb' + +# Offense count: 1 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +Style/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/machinist/blueprint.rb' diff --git a/.travis.yml b/.travis.yml index 6888b39..9cb689f 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,26 @@ +--- language: ruby + rvm: - ruby-head - - 2.1.0 - - 2.0.0 - - rbx-2.1.1 - - 1.9.3 - - jruby-19mode # JRuby in 1.9 mode - - rbx-19mode + - 2.4.1 + - 2.3.4 + - 2.2.6 + - 2.1.10 gemfile: - - gemfiles/3.0.gemfile - - gemfiles/3.1.gemfile - - gemfiles/3.2.gemfile - - gemfiles/4.0.gemfile - - gemfiles/4.1.gemfile - - gemfiles/4.2.gemfile + - gemfiles/rails_4.2.gemfile + - gemfiles/rails_5.0.gemfile + - gemfiles/rails_5.1.gemfile branches: only: - master + matrix: allow_failures: - - rvm: jruby-18mode - - rvm: jruby-19mode + - gemfile: gemfiles/rails_5.0.gemfile + rvm: 2.1.10 + - gemfile: gemfiles/rails_5.1.gemfile + rvm: 2.1.10 - rvm: ruby-head diff --git a/Appraisals b/Appraisals new file mode 100755 index 0000000..f76d745 --- /dev/null +++ b/Appraisals @@ -0,0 +1,11 @@ +appraise 'rails-4.2' do + gem 'activerecord', '~> 4.2.8', group: :test, require: false +end + +appraise 'rails-5.0' do + gem 'activerecord', '~> 5.0.3', group: :test, require: false +end + +appraise 'rails-5.1' do + gem 'activerecord', '~> 5.1.1', group: :test, require: false +end diff --git a/Gemfile b/Gemfile old mode 100644 new mode 100755 index 4bf5e22..72682e0 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,26 @@ -source "http://rubygems.org" +source 'http://rubygems.org' gemspec +ruby RUBY_VERSION + +group :development do + gem 'appraisal', require: false + gem 'rdoc', require: false + gem 'rubocop-rspec', require: false +end + +group :test do + gem 'codeclimate-test-reporter', require: false + gem 'coveralls', require: false + gem 'fuubar', require: false + gem 'rspec', require: false + gem 'rspec_junit_formatter', require: false + gem 'simplecov', '~> 0.14', require: false +end platforms :ruby do - gem "sqlite3" + gem 'sqlite3' end platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" + gem 'activerecord-jdbcsqlite3-adapter' end diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 50d4b56..3d7a059 --- a/README.md +++ b/README.md @@ -1,10 +1,18 @@ # Machinist 2 -*Fixtures aren't fun. Machinist is.* +*Fixtures aren't fun. Machinist was.* -- [Home page](http://github.com/liquid/machinist) +[![Gem version](https://badge.fury.io/rb/machinist.svg)](https://rubygems.org/gems/machinist) +[![Gem downloads](https://img.shields.io/gem/dt/machinist.svg)](https://rubygems.org/gems/machinist) +[![Build Status](https://travis-ci.org/dominicsayers/machinist.svg?branch=master)](https://travis-ci.org/dominicsayers/machinist) +[![Code Climate](https://codeclimate.com/github/dominicsayers/machinist/badges/gpa.svg)](https://codeclimate.com/github/dominicsayers/machinist) +[![Test Coverage](https://codeclimate.com/github/dominicsayers/machinist/badges/coverage.svg)](https://codeclimate.com/github/dominicsayers/machinist/coverage) +[![Dependency Status](https://gemnasium.com/badges/github.com/dominicsayers/machinist.svg)](https://gemnasium.com/github.com/dominicsayers/machinist) +[![Security](https://hakiri.io/github/dominicsayers/machinist/master.svg)](https://hakiri.io/github/dominicsayers/machinist/master) + +- [Home page](http://github.com/dominicsayers/machinist) - [Google group](http://groups.google.com/group/machinist-users), for support -- [Bug tracker](http://github.com/liquid/machinist/issues), for reporting Machinist bugs +- [Bug tracker](http://github.com/dominicsayers/machinist/issues), for reporting Machinist bugs If you want Machinist 1, [go here](http://github.com/notahat/machinist/tree/1.0-maintenance). @@ -218,14 +226,14 @@ You can refer to already assigned attributes when constructing a new attribute: Read the code! No, really. I wrote this code to be read. -Check out [the specs](https://github.com/notahat/machinist/tree/master/spec), +Check out [the specs](https://github.com/dominicsayers/machinist/tree/master/spec), starting with [the spec for -Machinable](https://github.com/notahat/machinist/blob/master/spec/machinable_spec.rb). +Machinable](https://github.com/dominicsayers/machinist/blob/master/spec/machinable_spec.rb). ## Compatibility -Please have a look at the Travis Build Status. [![Travis Build Status](https://travis-ci.org/liquid/machinist.png?branch=master)](https://travis-ci.org/liquid/machinist) +Please have a look at the Travis Build Status. [![Travis Build Status](https://travis-ci.org/dominicsayers/machinist.png?branch=master)](https://travis-ci.org/dominicsayers/machinist) I've tested this with: @@ -265,7 +273,7 @@ If anybody wants to take over maintenance, let me know. ## Contributors -Machinist is maintained by Pete Yandell ([pete@notahat.com](mailto:pete@notahat.com), [@notahat](http://twitter.com/notahat)) +Machinist was maintained by Pete Yandell ([pete@notahat.com](mailto:pete@notahat.com), [@notahat](http://twitter.com/notahat)) Other contributors include: @@ -290,6 +298,7 @@ Other contributors include: [Gareth Townsend](http://github.com/quamen), [Matt Wastrodowski](http://github.com/towski), [Ian White](http://github.com/ianwhite) +[Dominic Sayers](https://github.com/dominicsayers) Thanks to Thoughtbot's [Factory Girl](http://github.com/thoughtbot/factory_girl/tree/master). Machinist was diff --git a/Rakefile b/Rakefile old mode 100644 new mode 100755 index fdcaa9a..02d61ec --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,15 @@ -require "bundler/gem_tasks" +begin + require 'rubygems' + require 'bundler/setup' + require 'bundler/gem_tasks' + require 'rspec/core/rake_task' -require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new(:spec) + RSpec::Core::RakeTask.new(:spec) + + task default: :spec +rescue LoadError + puts 'rspec is not available' +end require 'rdoc/task' RDoc::Task.new(:rdoc) do |rdoc| @@ -10,5 +18,3 @@ RDoc::Task.new(:rdoc) do |rdoc| rdoc.options << '--line-numbers' rdoc.rdoc_files.include('lib') end - -task :default => :spec diff --git a/gemfiles/3.0.gemfile b/gemfiles/3.0.gemfile deleted file mode 100644 index 42e126c..0000000 --- a/gemfiles/3.0.gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -gem 'activerecord', '~> 3.0.20' - -platforms :ruby do - gem "sqlite3" -end - -platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" -end - -gemspec :path => '../' diff --git a/gemfiles/3.1.gemfile b/gemfiles/3.1.gemfile deleted file mode 100644 index bedd534..0000000 --- a/gemfiles/3.1.gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -gem 'activerecord', '~> 3.1.12' - -platforms :ruby do - gem "sqlite3" -end - -platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" -end - -gemspec :path => '../' diff --git a/gemfiles/3.2.gemfile b/gemfiles/3.2.gemfile deleted file mode 100644 index bde4ca7..0000000 --- a/gemfiles/3.2.gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -gem 'activerecord', '~> 3.2.16' - -platforms :ruby do - gem "sqlite3" -end - -platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" -end - -gemspec :path => '../' diff --git a/gemfiles/4.0.gemfile b/gemfiles/4.0.gemfile deleted file mode 100644 index c9fcda0..0000000 --- a/gemfiles/4.0.gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -gem 'activerecord', '~> 4.0.2' - -platforms :ruby do - gem "sqlite3" -end - -platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" -end - -gemspec :path => '../' diff --git a/gemfiles/4.1.beta.gemfile b/gemfiles/4.1.beta.gemfile deleted file mode 100644 index 0e3b050..0000000 --- a/gemfiles/4.1.beta.gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -gem 'activerecord', '~> 4.1.0.beta1' - -platforms :ruby do - gem "sqlite3" -end - -platforms :jruby do - gem "activerecord-jdbcsqlite3-adapter" -end - -gemspec :path => '../' diff --git a/gemfiles/rails_4.2.gemfile b/gemfiles/rails_4.2.gemfile new file mode 100755 index 0000000..51a17fe --- /dev/null +++ b/gemfiles/rails_4.2.gemfile @@ -0,0 +1,32 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +ruby RUBY_VERSION + +gem "activerecord", "~> 4.2.8", group: :test, require: false + +group :development do + gem "appraisal", require: false + gem "rdoc", require: false + gem "rubocop-rspec", require: false +end + +group :test do + gem "codeclimate-test-reporter", require: false + gem "coveralls", require: false + gem "fuubar", require: false + gem "rspec", require: false + gem "rspec_junit_formatter", require: false + gem "simplecov", "~> 0.14", require: false +end + +platforms :ruby do + gem "sqlite3" +end + +platforms :jruby do + gem "activerecord-jdbcsqlite3-adapter" +end + +gemspec path: "../" diff --git a/gemfiles/rails_4.2.gemfile.lock b/gemfiles/rails_4.2.gemfile.lock new file mode 100644 index 0000000..ffee889 --- /dev/null +++ b/gemfiles/rails_4.2.gemfile.lock @@ -0,0 +1,113 @@ +PATH + remote: .. + specs: + machinist (2.0) + +GEM + remote: http://rubygems.org/ + specs: + activemodel (4.2.8) + activesupport (= 4.2.8) + builder (~> 3.1) + activerecord (4.2.8) + activemodel (= 4.2.8) + activesupport (= 4.2.8) + arel (~> 6.0) + activesupport (4.2.8) + i18n (~> 0.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (6.0.4) + ast (2.3.0) + builder (3.2.3) + codeclimate-test-reporter (1.0.7) + simplecov + coveralls (0.8.21) + json (>= 1.8, < 3) + simplecov (~> 0.14.1) + term-ansicolor (~> 1.3) + thor (~> 0.19.4) + tins (~> 1.6) + diff-lcs (1.3) + docile (1.1.5) + fuubar (2.2.0) + rspec-core (~> 3.0) + ruby-progressbar (~> 1.4) + i18n (0.8.1) + json (2.1.0) + minitest (5.10.2) + parser (2.4.0.0) + ast (~> 2.2) + powerpack (0.1.1) + rainbow (2.2.2) + rake + rake (12.0.0) + rdoc (5.1.0) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) + rspec_junit_formatter (0.2.3) + builder (< 4) + rspec-core (>= 2, < 4, != 2.12.0) + rubocop (0.48.1) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-rspec (1.15.1) + rubocop (>= 0.42.0) + ruby-progressbar (1.8.1) + simplecov (0.14.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + sqlite3 (1.3.13) + term-ansicolor (1.6.0) + tins (~> 1.0) + thor (0.19.4) + thread_safe (0.3.6) + tins (1.13.3) + tzinfo (1.2.3) + thread_safe (~> 0.1) + unicode-display_width (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord (~> 4.2.8) + activerecord-jdbcsqlite3-adapter + appraisal + codeclimate-test-reporter + coveralls + fuubar + machinist! + rdoc + rspec + rspec_junit_formatter + rubocop-rspec + simplecov (~> 0.14) + sqlite3 + +RUBY VERSION + ruby 2.3.4p301 + +BUNDLED WITH + 1.14.6 diff --git a/gemfiles/rails_5.0.gemfile b/gemfiles/rails_5.0.gemfile new file mode 100755 index 0000000..82059d3 --- /dev/null +++ b/gemfiles/rails_5.0.gemfile @@ -0,0 +1,32 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +ruby RUBY_VERSION + +gem "activerecord", "~> 5.0.3", group: :test, require: false + +group :development do + gem "appraisal", require: false + gem "rdoc", require: false + gem "rubocop-rspec", require: false +end + +group :test do + gem "codeclimate-test-reporter", require: false + gem "coveralls", require: false + gem "fuubar", require: false + gem "rspec", require: false + gem "rspec_junit_formatter", require: false + gem "simplecov", "~> 0.14", require: false +end + +platforms :ruby do + gem "sqlite3" +end + +platforms :jruby do + gem "activerecord-jdbcsqlite3-adapter" +end + +gemspec path: "../" diff --git a/gemfiles/rails_5.0.gemfile.lock b/gemfiles/rails_5.0.gemfile.lock new file mode 100644 index 0000000..2f36786 --- /dev/null +++ b/gemfiles/rails_5.0.gemfile.lock @@ -0,0 +1,113 @@ +PATH + remote: .. + specs: + machinist (2.0) + +GEM + remote: http://rubygems.org/ + specs: + activemodel (5.0.3) + activesupport (= 5.0.3) + activerecord (5.0.3) + activemodel (= 5.0.3) + activesupport (= 5.0.3) + arel (~> 7.0) + activesupport (5.0.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (7.1.4) + ast (2.3.0) + builder (3.2.3) + codeclimate-test-reporter (1.0.7) + simplecov + concurrent-ruby (1.0.5) + coveralls (0.8.21) + json (>= 1.8, < 3) + simplecov (~> 0.14.1) + term-ansicolor (~> 1.3) + thor (~> 0.19.4) + tins (~> 1.6) + diff-lcs (1.3) + docile (1.1.5) + fuubar (2.2.0) + rspec-core (~> 3.0) + ruby-progressbar (~> 1.4) + i18n (0.8.1) + json (2.1.0) + minitest (5.10.2) + parser (2.4.0.0) + ast (~> 2.2) + powerpack (0.1.1) + rainbow (2.2.2) + rake + rake (12.0.0) + rdoc (5.1.0) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) + rspec_junit_formatter (0.2.3) + builder (< 4) + rspec-core (>= 2, < 4, != 2.12.0) + rubocop (0.48.1) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-rspec (1.15.1) + rubocop (>= 0.42.0) + ruby-progressbar (1.8.1) + simplecov (0.14.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + sqlite3 (1.3.13) + term-ansicolor (1.6.0) + tins (~> 1.0) + thor (0.19.4) + thread_safe (0.3.6) + tins (1.13.3) + tzinfo (1.2.3) + thread_safe (~> 0.1) + unicode-display_width (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord (~> 5.0.3) + activerecord-jdbcsqlite3-adapter + appraisal + codeclimate-test-reporter + coveralls + fuubar + machinist! + rdoc + rspec + rspec_junit_formatter + rubocop-rspec + simplecov (~> 0.14) + sqlite3 + +RUBY VERSION + ruby 2.3.4p301 + +BUNDLED WITH + 1.14.6 diff --git a/gemfiles/rails_5.1.gemfile b/gemfiles/rails_5.1.gemfile new file mode 100755 index 0000000..a4a49e9 --- /dev/null +++ b/gemfiles/rails_5.1.gemfile @@ -0,0 +1,32 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +ruby RUBY_VERSION + +gem "activerecord", "~> 5.1.1", group: :test, require: false + +group :development do + gem "appraisal", require: false + gem "rdoc", require: false + gem "rubocop-rspec", require: false +end + +group :test do + gem "codeclimate-test-reporter", require: false + gem "coveralls", require: false + gem "fuubar", require: false + gem "rspec", require: false + gem "rspec_junit_formatter", require: false + gem "simplecov", "~> 0.14", require: false +end + +platforms :ruby do + gem "sqlite3" +end + +platforms :jruby do + gem "activerecord-jdbcsqlite3-adapter" +end + +gemspec path: "../" diff --git a/gemfiles/rails_5.1.gemfile.lock b/gemfiles/rails_5.1.gemfile.lock new file mode 100644 index 0000000..b39ad5b --- /dev/null +++ b/gemfiles/rails_5.1.gemfile.lock @@ -0,0 +1,113 @@ +PATH + remote: .. + specs: + machinist (2.0) + +GEM + remote: http://rubygems.org/ + specs: + activemodel (5.1.1) + activesupport (= 5.1.1) + activerecord (5.1.1) + activemodel (= 5.1.1) + activesupport (= 5.1.1) + arel (~> 8.0) + activesupport (5.1.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + arel (8.0.0) + ast (2.3.0) + builder (3.2.3) + codeclimate-test-reporter (1.0.7) + simplecov + concurrent-ruby (1.0.5) + coveralls (0.8.21) + json (>= 1.8, < 3) + simplecov (~> 0.14.1) + term-ansicolor (~> 1.3) + thor (~> 0.19.4) + tins (~> 1.6) + diff-lcs (1.3) + docile (1.1.5) + fuubar (2.2.0) + rspec-core (~> 3.0) + ruby-progressbar (~> 1.4) + i18n (0.8.1) + json (2.1.0) + minitest (5.10.2) + parser (2.4.0.0) + ast (~> 2.2) + powerpack (0.1.1) + rainbow (2.2.2) + rake + rake (12.0.0) + rdoc (5.1.0) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) + rspec_junit_formatter (0.2.3) + builder (< 4) + rspec-core (>= 2, < 4, != 2.12.0) + rubocop (0.48.1) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-rspec (1.15.1) + rubocop (>= 0.42.0) + ruby-progressbar (1.8.1) + simplecov (0.14.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + sqlite3 (1.3.13) + term-ansicolor (1.6.0) + tins (~> 1.0) + thor (0.19.4) + thread_safe (0.3.6) + tins (1.13.3) + tzinfo (1.2.3) + thread_safe (~> 0.1) + unicode-display_width (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord (~> 5.1.1) + activerecord-jdbcsqlite3-adapter + appraisal + codeclimate-test-reporter + coveralls + fuubar + machinist! + rdoc + rspec + rspec_junit_formatter + rubocop-rspec + simplecov (~> 0.14) + sqlite3 + +RUBY VERSION + ruby 2.3.4p301 + +BUNDLED WITH + 1.14.6 diff --git a/lib/generators/machinist/install/install_generator.rb b/lib/generators/machinist/install/install_generator.rb index 3840062..9ff51bf 100644 --- a/lib/generators/machinist/install/install_generator.rb +++ b/lib/generators/machinist/install/install_generator.rb @@ -3,20 +3,20 @@ module Generators #:nodoc: class InstallGenerator < Rails::Generators::Base #:nodoc: source_root File.expand_path('../templates', __FILE__) - class_option :test_framework, :type => :string, :aliases => "-t", :desc => "Test framework to use Machinist with" - class_option :cucumber, :type => :boolean, :desc => "Set up access to Machinist from Cucumber" + class_option :test_framework, type: :string, aliases: '-t', desc: 'Test framework to use Machinist with' + class_option :cucumber, type: :boolean, desc: 'Set up access to Machinist from Cucumber' def blueprints_file if rspec? - copy_file "blueprints.rb", "spec/support/blueprints.rb" + copy_file 'blueprints.rb', 'spec/support/blueprints.rb' else - copy_file "blueprints.rb", "test/blueprints.rb" + copy_file 'blueprints.rb', 'test/blueprints.rb' end end def test_helper if test_unit? - inject_into_file("test/test_helper.rb", :after => "require 'rails/test_help'\n") do + inject_into_file('test/test_helper.rb', after: "require 'rails/test_help'\n") do "require File.expand_path(File.dirname(__FILE__) + '/blueprints')\n" end end @@ -24,11 +24,11 @@ def test_helper def cucumber_support if cucumber? - template "machinist.rb.erb", "features/support/machinist.rb" + template 'machinist.rb.erb', 'features/support/machinist.rb' end end - private + private def rspec? options[:test_framework].to_sym == :rspec diff --git a/lib/generators/machinist/model/model_generator.rb b/lib/generators/machinist/model/model_generator.rb index 6027950..d18df41 100644 --- a/lib/generators/machinist/model/model_generator.rb +++ b/lib/generators/machinist/model/model_generator.rb @@ -1,13 +1,11 @@ module Machinist module Generators #:nodoc: class ModelGenerator < Rails::Generators::NamedBase #:nodoc: - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + argument :attributes, type: :array, default: [], banner: 'field:type field:type' def create_blueprint - append_file "spec/support/blueprints.rb", "\n#{class_name}.blueprint do\n # Attributes here\nend\n" + append_file 'spec/support/blueprints.rb', "\n#{class_name}.blueprint do\n # Attributes here\nend\n" end - end end end - diff --git a/lib/machinist.rb b/lib/machinist.rb index b9366cf..f7ed011 100644 --- a/lib/machinist.rb +++ b/lib/machinist.rb @@ -3,4 +3,3 @@ require 'machinist/exceptions' require 'machinist/lathe' require 'machinist/machinable' - diff --git a/lib/machinist/active_record/blueprint.rb b/lib/machinist/active_record/blueprint.rb index a226b7e..35616be 100644 --- a/lib/machinist/active_record/blueprint.rb +++ b/lib/machinist/active_record/blueprint.rb @@ -1,6 +1,5 @@ module Machinist::ActiveRecord class Blueprint < Machinist::Blueprint - # Make and save an object. def make!(attributes = {}) object = make(attributes) @@ -11,6 +10,5 @@ def make!(attributes = {}) def lathe_class #:nodoc: Machinist::ActiveRecord::Lathe end - end end diff --git a/lib/machinist/active_record/lathe.rb b/lib/machinist/active_record/lathe.rb index fc1f335..d5e8f0e 100644 --- a/lib/machinist/active_record/lathe.rb +++ b/lib/machinist/active_record/lathe.rb @@ -1,7 +1,5 @@ module Machinist::ActiveRecord - class Lathe < Machinist::Lathe - def make_one_value(attribute, args) #:nodoc: if block_given? raise_argument_error(attribute) unless args.empty? @@ -19,6 +17,5 @@ def make_association(attribute, args) #:nodoc: raise_argument_error(attribute) end end - end end diff --git a/lib/machinist/blueprint.rb b/lib/machinist/blueprint.rb index 3411e29..4ff6fa8 100644 --- a/lib/machinist/blueprint.rb +++ b/lib/machinist/blueprint.rb @@ -1,8 +1,6 @@ module Machinist - # A Blueprint defines a method of constructing objects of a particular class. class Blueprint - # Construct a blueprint for the given +klass+. # # Pass in the +:parent+ option to define a parent blueprint to apply after @@ -24,7 +22,7 @@ def make(attributes = {}) lathe = lathe_class.new(@klass, new_serial_number, attributes) lathe.instance_eval(&@block) - each_ancestor {|blueprint| lathe.instance_eval(&blueprint.block) } + each_ancestor { |blueprint| lathe.instance_eval(&blueprint.block) } lathe.object end @@ -39,14 +37,14 @@ def lathe_class # Returns the parent blueprint for this blueprint. def parent_blueprint case @parent - when nil - nil - when Blueprint - # @parent references the parent blueprint directly. - @parent - else - # @parent is a class in which we should look for a blueprint. - find_blueprint_in_superclass_chain(@parent) + when nil + nil + when Blueprint + # @parent references the parent blueprint directly. + @parent + else + # @parent is a class in which we should look for a blueprint. + find_blueprint_in_superclass_chain(@parent) end end @@ -59,31 +57,28 @@ def each_ancestor end end - protected + protected - def new_serial_number #:nodoc: - parent_blueprint = self.parent_blueprint # Cache this for speed. + def new_serial_number #:nodoc: + parent_blueprint = self.parent_blueprint # Cache this for speed. if parent_blueprint parent_blueprint.new_serial_number else @serial_number ||= 0 @serial_number += 1 - sprintf("%04d", @serial_number) + sprintf('%04d', @serial_number) end end - private + private def find_blueprint_in_superclass_chain(klass) - until has_blueprint?(klass) || klass.nil? - klass = klass.superclass - end + klass = klass.superclass until has_blueprint?(klass) || klass.nil? klass && klass.blueprint end def has_blueprint?(klass) klass.respond_to?(:blueprint) && !klass.blueprint.nil? end - end end diff --git a/lib/machinist/exceptions.rb b/lib/machinist/exceptions.rb index a6072dc..6dc51b3 100644 --- a/lib/machinist/exceptions.rb +++ b/lib/machinist/exceptions.rb @@ -1,5 +1,4 @@ module Machinist - # Raised when make! is called on a class whose blueprints don't support # saving. class BlueprintCantSaveError < RuntimeError @@ -28,5 +27,4 @@ def message "No #{@name} blueprint defined for class #{@klass.name}" end end - end diff --git a/lib/machinist/lathe.rb b/lib/machinist/lathe.rb old mode 100644 new mode 100755 index 87ed61d..7b8bcad --- a/lib/machinist/lathe.rb +++ b/lib/machinist/lathe.rb @@ -1,19 +1,17 @@ module Machinist - # When you make an object, the blueprint for that object is instance-evaled # against a Lathe. # # The Lathe implements all the methods that are available to the blueprint, # including method_missing to let the blueprint define attributes. class Lathe - def initialize(klass, serial_number, attributes = {}) @klass = klass @serial_number = serial_number @assigned_attributes = {} @object = @klass.new - attributes.each {|key, value| assign_attribute(key, value) } + attributes.each { |key, value| assign_attribute(key, value) } end # Returns a unique serial number for the object under construction. @@ -35,10 +33,10 @@ def method_missing(attribute, *args, &block) #:nodoc: undef_method :id if respond_to?(:id) undef_method :type if respond_to?(:type) - protected + protected def make_attribute(attribute, args, &block) #:nodoc: - count = args.shift if args.first.is_a?(Fixnum) + count = args.shift if args.first.is_a?(0.class) if count Array.new(count) { make_one_value(attribute, args, &block) } else @@ -57,12 +55,11 @@ def assign_attribute(key, value) #:nodoc: end def attribute_assigned?(key) #:nodoc: - @assigned_attributes.has_key?(key.to_sym) + @assigned_attributes.key?(key.to_sym) end def raise_argument_error(attribute) #:nodoc: - raise ArgumentError.new("Invalid arguments to attribute #{attribute} in blueprint") + raise ArgumentError, "Invalid arguments to attribute #{attribute} in blueprint" end - end end diff --git a/lib/machinist/machinable.rb b/lib/machinist/machinable.rb old mode 100644 new mode 100755 index 202593f..e79af5b --- a/lib/machinist/machinable.rb +++ b/lib/machinist/machinable.rb @@ -1,5 +1,4 @@ module Machinist - # Extend classes with this module to define the blueprint and make methods. module Machinable # Define a blueprint with the given name for this class. @@ -16,7 +15,7 @@ def blueprint(name = :master, &block) @blueprints ||= {} if block_given? parent = (name == :master ? superclass : self) # Where should we look for the parent blueprint? - @blueprints[name] = blueprint_class.new(self, :parent => parent, &block) + @blueprints[name] = blueprint_class.new(self, parent: parent, &block) end @blueprints[name] end @@ -48,7 +47,7 @@ def make(*args) # Arguments are the same as for make. def make!(*args) decode_args_to_make(*args) do |blueprint, attributes| - raise BlueprintCantSaveError.new(blueprint) unless blueprint.respond_to?(:make!) + raise BlueprintCantSaveError, blueprint unless blueprint.respond_to?(:make!) blueprint.make!(attributes) end end @@ -66,7 +65,7 @@ def blueprint_class Machinist::Blueprint end - private + private # Parses the arguments to make. # @@ -74,15 +73,8 @@ def blueprint_class # construct an object from them. The block may be called multiple times to # construct multiple objects. def decode_args_to_make(*args) #:nodoc: - shift_arg = lambda {|klass| args.shift if args.first.is_a?(klass) } - count = shift_arg[Fixnum] - name = shift_arg[Symbol] || :master - attributes = shift_arg[Hash] || {} - raise ArgumentError.new("Couldn't understand arguments") unless args.empty? - - @blueprints ||= {} - blueprint = @blueprints[name] - raise NoBlueprintError.new(self, name) unless blueprint + count, name, attributes = *decode_args(args) + blueprint = ensure_blueprint(name) if count.nil? yield(blueprint, attributes) @@ -91,5 +83,18 @@ def decode_args_to_make(*args) #:nodoc: end end + def decode_args(args) + shift_arg = ->(klass) { args.shift if args.first.is_a?(klass) } + count = shift_arg[0.class] + name = shift_arg[Symbol] || :master + attributes = shift_arg[Hash] || {} + raise ArgumentError, "Couldn't understand arguments" unless args.empty? + [count, name, attributes] + end + + def ensure_blueprint(name) + @blueprints ||= {} + @blueprints[name] || raise(NoBlueprintError.new(self, name)) + end end end diff --git a/lib/machinist/version.rb b/lib/machinist/version.rb index be549e6..ce22243 100644 --- a/lib/machinist/version.rb +++ b/lib/machinist/version.rb @@ -1,3 +1,3 @@ module Machinist - VERSION = "2.0" + VERSION = '2.0'.freeze end diff --git a/machinist.gemspec b/machinist.gemspec old mode 100644 new mode 100755 index 3237a63..77bd979 --- a/machinist.gemspec +++ b/machinist.gemspec @@ -1,24 +1,22 @@ # -*- encoding: utf-8 -*- + lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'machinist/version' Gem::Specification.new do |gem| - gem.name = "machinist" + gem.name = 'machinist' gem.version = Machinist::VERSION - gem.authors = ["Pete Yandell", "Attila Györffy"] - gem.email = ["attila@attilagyorffy.com"] - gem.description = %q{Machinist makes it easy to create objects for use in tests. It generates data for the attributes you don't care about, and constructs any necessary associated objects, leaving you to specify only the fields you care about in your test.} - gem.summary = %q{Fixtures aren't fun. Machinist is.} - gem.homepage = "http://github.com/liquid/machinist" - - gem.add_development_dependency "activerecord" - gem.add_development_dependency "rake" - gem.add_development_dependency "rspec" - gem.add_development_dependency "rdoc" + gem.authors = ['Pete Yandell', 'Attila Györffy', 'Dominic Sayers'] + gem.email = ['dominic@sayers.cc'] + gem.description = 'Machinist makes it easy to create objects for use in tests. It generates data for the ' \ + "attributes you don't care about, and constructs any necessary associated objects, leaving you "\ + 'to specify only the fields you care about in your test.' + gem.summary = "Fixtures aren't fun. Machinist is." + gem.homepage = 'http://github.com/liquid/machinist' - gem.files = `git ls-files`.split($/) - gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR) + gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) - gem.require_paths = ["lib"] + gem.require_paths = ['lib'] end diff --git a/spec/active_record_spec.rb b/spec/active_record_spec.rb deleted file mode 100644 index b8412e3..0000000 --- a/spec/active_record_spec.rb +++ /dev/null @@ -1,108 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' -require 'support/active_record_environment' - -describe Machinist::ActiveRecord do - include ActiveRecordEnvironment - - before(:each) do - empty_database! - end - - context "make" do - it "returns an unsaved object" do - Post.blueprint { } - post = Post.make - post.should be_a(Post) - post.should be_new_record - end - end - - context "make!" do - it "makes and saves objects" do - Post.blueprint { } - post = Post.make! - post.should be_a(Post) - post.should_not be_new_record - end - - it "raises an exception for an invalid object" do - User.blueprint { } - lambda { - User.make!(:username => "") - }.should raise_error(ActiveRecord::RecordInvalid) - end - end - - context "associations support" do - it "handles belongs_to associations" do - User.blueprint do - username { "user_#{sn}" } - end - Post.blueprint do - author - end - post = Post.make! - post.should be_a(Post) - post.should_not be_new_record - post.author.should be_a(User) - post.author.should_not be_new_record - end - - it "handles has_many associations" do - Post.blueprint do - comments(3) - end - Comment.blueprint { } - post = Post.make! - post.should be_a(Post) - post.should_not be_new_record - post.should have(3).comments - post.comments.each do |comment| - comment.should be_a(Comment) - comment.should_not be_new_record - end - end - - it "handles habtm associations" do - Post.blueprint do - tags(3) - end - Tag.blueprint do - name { "tag_#{sn}" } - end - post = Post.make! - post.should be_a(Post) - post.should_not be_new_record - post.should have(3).tags - post.tags.each do |tag| - tag.should be_a(Tag) - tag.should_not be_new_record - end - end - - it "handles overriding associations" do - User.blueprint do - username { "user_#{sn}" } - end - Post.blueprint do - author { User.make(:username => "post_author_#{sn}") } - end - post = Post.make! - post.should be_a(Post) - post.should_not be_new_record - post.author.should be_a(User) - post.author.should_not be_new_record - post.author.username.should =~ /^post_author_\d+$/ - end - end - - context "error handling" do - it "raises an exception for an attribute with no value" do - User.blueprint { username } - lambda { - User.make - }.should raise_error(ArgumentError) - end - end - -end diff --git a/spec/blueprint_spec.rb b/spec/blueprint_spec.rb deleted file mode 100644 index 4c02034..0000000 --- a/spec/blueprint_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' -require 'ostruct' - -describe Machinist::Blueprint do - - it "makes an object of the given class" do - blueprint = Machinist::Blueprint.new(OpenStruct) { } - blueprint.make.should be_an(OpenStruct) - end - - it "constructs an attribute from the blueprint" do - blueprint = Machinist::Blueprint.new(OpenStruct) do - name { "Fred" } - end - blueprint.make.name.should == "Fred" - end - - it "constructs an array for an attribute in the blueprint" do - blueprint = Machinist::Blueprint.new(OpenStruct) do - things(3) { Object.new } - end - things = blueprint.make.things - things.should be_an(Array) - things.should have(3).elements - things.each {|thing| thing.should be_an(Object) } - things.uniq.should == things - end - - it "allows passing in attributes to override the blueprint" do - block_called = false - blueprint = Machinist::Blueprint.new(OpenStruct) do - name { block_called = true; "Fred" } - end - blueprint.make(:name => "Bill").name.should == "Bill" - block_called.should be_false - end - - it "provides a serial number within the blueprint" do - blueprint = Machinist::Blueprint.new(OpenStruct) do - name { "Fred #{sn}" } - end - blueprint.make.name.should == "Fred 0001" - blueprint.make.name.should == "Fred 0002" - end - - it "provides access to the object being constructed within the blueprint" do - blueprint = Machinist::Blueprint.new(OpenStruct) do - title { "Test" } - body { object.title } - end - blueprint.make.body.should == "Test" - end - - it "allows attribute names to be strings" do - blueprint = Machinist::Blueprint.new(OpenStruct) do - name { "Fred" } - end - blueprint.make("name" => "Bill").name.should == "Bill" - end - - # These are normally a problem because of name clashes with the standard (but - # deprecated) Ruby methods. This test makes sure we work around this. - it "works with type and id attributes" do - klass = Class.new do - attr_accessor :id, :type - end - blueprint = Machinist::Blueprint.new(klass) do - id { "custom id" } - type { "custom type" } - end - object = blueprint.make - object.id.should == "custom id" - object.type.should == "custom type" - end - -end diff --git a/spec/exceptions_spec.rb b/spec/exceptions_spec.rb deleted file mode 100644 index c6b84af..0000000 --- a/spec/exceptions_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' - -describe Machinist, "exceptions" do - - describe Machinist::BlueprintCantSaveError do - it "presents the right message" do - blueprint = Machinist::Blueprint.new(String) { } - exception = Machinist::BlueprintCantSaveError.new(blueprint) - exception.message.should == "make! is not supported by blueprints for class String" - end - end - - describe Machinist::NoBlueprintError do - it "presents the right message" do - exception = Machinist::NoBlueprintError.new(String, :master) - exception.message.should == "No master blueprint defined for class String" - end - end - -end diff --git a/spec/inheritance_spec.rb b/spec/inheritance_spec.rb deleted file mode 100644 index cbe1cf6..0000000 --- a/spec/inheritance_spec.rb +++ /dev/null @@ -1,104 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' -require 'ostruct' - -module InheritanceSpecs - class Grandpa - extend Machinist::Machinable - attr_accessor :name, :age - end - - class Dad < Grandpa - extend Machinist::Machinable - attr_accessor :name, :age - end - - class Son < Dad - extend Machinist::Machinable - attr_accessor :name, :age - end -end - -describe Machinist::Blueprint do - - describe "explicit inheritance" do - it "inherits attributes from the parent blueprint" do - parent_blueprint = Machinist::Blueprint.new(OpenStruct) do - name { "Fred" } - age { 97 } - end - - child_blueprint = Machinist::Blueprint.new(OpenStruct, :parent => parent_blueprint) do - name { "Bill" } - end - - child = child_blueprint.make - child.name.should == "Bill" - child.age.should == 97 - end - - it "takes the serial number from the parent" do - parent_blueprint = Machinist::Blueprint.new(OpenStruct) do - parent_serial { sn } - end - - child_blueprint = Machinist::Blueprint.new(OpenStruct, :parent => parent_blueprint) do - child_serial { sn } - end - - parent_blueprint.make.parent_serial.should == "0001" - child_blueprint.make.child_serial.should == "0002" - parent_blueprint.make.parent_serial.should == "0003" - end - end - - describe "class inheritance" do - before(:each) do - [InheritanceSpecs::Grandpa, InheritanceSpecs::Dad, InheritanceSpecs::Son].each(&:clear_blueprints!) - end - - it "inherits blueprinted attributes from the parent class" do - InheritanceSpecs::Dad.blueprint do - name { "Fred" } - end - InheritanceSpecs::Son.blueprint { } - InheritanceSpecs::Son.make.name.should == "Fred" - end - - it "overrides blueprinted attributes in the child class" do - InheritanceSpecs::Dad.blueprint do - name { "Fred" } - end - InheritanceSpecs::Son.blueprint do - name { "George" } - end - InheritanceSpecs::Dad.make.name.should == "Fred" - InheritanceSpecs::Son.make.name.should == "George" - end - - it "inherits from blueprinted attributes in ancestor class" do - InheritanceSpecs::Grandpa.blueprint do - name { "Fred" } - end - InheritanceSpecs::Son.blueprint { } - InheritanceSpecs::Grandpa.make.name.should == "Fred" - lambda { InheritanceSpecs::Dad.make }.should raise_error(RuntimeError) - InheritanceSpecs::Son.make.name.should == "Fred" - end - - it "follows inheritance for named blueprints correctly" do - InheritanceSpecs::Dad.blueprint do - name { "John" } - age { 56 } - end - InheritanceSpecs::Dad.blueprint(:special) do - name { "Paul" } - end - InheritanceSpecs::Son.blueprint(:special) do - age { 37 } - end - InheritanceSpecs::Son.make(:special).name.should == "John" - InheritanceSpecs::Son.make(:special).age.should == 37 - end - end - -end diff --git a/spec/machinable_spec.rb b/spec/machinable_spec.rb deleted file mode 100644 index fd659bf..0000000 --- a/spec/machinable_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' - -module MachinableSpecs - class Post - extend Machinist::Machinable - attr_accessor :title, :body, :comments - end - - class Comment - extend Machinist::Machinable - attr_accessor :post, :title - end -end - -describe Machinist::Machinable do - - before(:each) do - MachinableSpecs::Post.clear_blueprints! - end - - it "makes an object" do - MachinableSpecs::Post.blueprint do - title { "First Post" } - end - - post = MachinableSpecs::Post.make - post.should be_a(MachinableSpecs::Post) - post.title.should == "First Post" - end - - it "makes an object from a named blueprint" do - MachinableSpecs::Post.blueprint do - title { "First Post" } - body { "Woot!" } - end - - MachinableSpecs::Post.blueprint(:extra) do - title { "Extra!" } - end - - post = MachinableSpecs::Post.make(:extra) - post.should be_a(MachinableSpecs::Post) - post.title.should == "Extra!" - post.body.should == "Woot!" - end - - it "makes an array of objects" do - MachinableSpecs::Post.blueprint do - title { "First Post" } - end - - posts = MachinableSpecs::Post.make(3) - posts.should be_an(Array) - posts.should have(3).elements - posts.each do |post| - post.should be_a(MachinableSpecs::Post) - post.title.should == "First Post" - end - end - - it "makes array attributes from the blueprint" do - MachinableSpecs::Comment.blueprint { } - MachinableSpecs::Post.blueprint do - comments(3) { MachinableSpecs::Comment.make } - end - - post = MachinableSpecs::Post.make - post.comments.should be_a(Array) - post.comments.should have(3).elements - post.comments.each do |comment| - comment.should be_a(MachinableSpecs::Comment) - end - end - - it "fails without a blueprint" do - expect { MachinableSpecs::Post.make }.to raise_error(Machinist::NoBlueprintError) do |exception| - exception.klass.should == MachinableSpecs::Post - exception.name.should == :master - end - - expect { MachinableSpecs::Post.make(:some_name) }.to raise_error(Machinist::NoBlueprintError) do |exception| - exception.klass.should == MachinableSpecs::Post - exception.name.should == :some_name - end - end - - it "fails when calling make! on an unsavable object" do - MachinableSpecs::Post.blueprint { } - - expect { MachinableSpecs::Post.make! }.to raise_error(Machinist::BlueprintCantSaveError) do |exception| - exception.blueprint.klass.should == MachinableSpecs::Post - end - end - -end diff --git a/spec/machinist/active_record_spec.rb b/spec/machinist/active_record_spec.rb new file mode 100755 index 0000000..2ed4b39 --- /dev/null +++ b/spec/machinist/active_record_spec.rb @@ -0,0 +1,106 @@ +require 'support/active_record_environment' + +RSpec.describe Machinist::ActiveRecord do + include ActiveRecordEnvironment + + before do + empty_database! + end + + context 'make' do + it 'returns an unsaved object' do + Post.blueprint {} + post = Post.make + expect(post).to be_a(Post) + expect(post).to be_new_record + end + end + + context 'make!' do + it 'makes and saves objects' do + Post.blueprint {} + post = Post.make! + expect(post).to be_a(Post) + expect(post).not_to be_new_record + end + + it 'raises an exception for an invalid object' do + User.blueprint {} + expect do + User.make!(username: '') + end.to raise_error(ActiveRecord::RecordInvalid) + end + end + + context 'associations support' do + it 'handles belongs_to associations' do + User.blueprint do + username { "user_#{sn}" } + end + Post.blueprint do + author + end + post = Post.make! + expect(post).to be_a(Post) + expect(post).not_to be_new_record + expect(post.author).to be_a(User) + expect(post.author).not_to be_new_record + end + + it 'handles has_many associations' do + Post.blueprint do + comments(3) + end + Comment.blueprint {} + post = Post.make! + expect(post).to be_a(Post) + expect(post).not_to be_new_record + expect(post.comments.size).to eq(3) + post.comments.each do |comment| + expect(comment).to be_a(Comment) + expect(comment).not_to be_new_record + end + end + + it 'handles habtm associations' do + Post.blueprint do + tags(3) + end + Tag.blueprint do + name { "tag_#{sn}" } + end + post = Post.make! + expect(post).to be_a(Post) + expect(post).not_to be_new_record + expect(post.tags.size).to eq(3) + post.tags.each do |tag| + expect(tag).to be_a(Tag) + expect(tag).not_to be_new_record + end + end + + it 'handles overriding associations' do + User.blueprint do + username { "user_#{sn}" } + end + Post.blueprint do + author { User.make(username: "post_author_#{sn}") } + end + post = Post.make! + expect(post).to be_a(Post) + expect(post).not_to be_new_record + expect(post.author).to be_a(User) + expect(post.author).not_to be_new_record + expect(post.author.username).to match(/^post_author_\d+$/) + end + end + + context 'error handling' do + it 'raises an exception for an attribute with no value' do + User.blueprint { username } + expect do + User.make + end.to raise_error(ArgumentError) + end + end +end diff --git a/spec/machinist/blueprint_inheritance_spec.rb b/spec/machinist/blueprint_inheritance_spec.rb new file mode 100755 index 0000000..3b86a08 --- /dev/null +++ b/spec/machinist/blueprint_inheritance_spec.rb @@ -0,0 +1,101 @@ +require 'ostruct' + +module InheritanceSpecs + class Grandpa + extend Machinist::Machinable + attr_accessor :name, :age + end + + class Dad < Grandpa + extend Machinist::Machinable + attr_accessor :name, :age + end + + class Son < Dad + extend Machinist::Machinable + attr_accessor :name, :age + end +end + +RSpec.describe Machinist::Blueprint do + describe 'explicit inheritance' do + it 'inherits attributes from the parent blueprint' do + parent_blueprint = described_class.new(OpenStruct) do + name { 'Fred' } + age { 97 } + end + + child_blueprint = described_class.new(OpenStruct, parent: parent_blueprint) do + name { 'Bill' } + end + + child = child_blueprint.make + expect(child.name).to eq('Bill') + expect(child.age).to eq(97) + end + + it 'takes the serial number from the parent' do + parent_blueprint = described_class.new(OpenStruct) do + parent_serial { sn } + end + + child_blueprint = described_class.new(OpenStruct, parent: parent_blueprint) do + child_serial { sn } + end + + expect(parent_blueprint.make.parent_serial).to eq('0001') + expect(child_blueprint.make.child_serial).to eq('0002') + expect(parent_blueprint.make.parent_serial).to eq('0003') + end + end + + describe 'class inheritance' do + before do + [InheritanceSpecs::Grandpa, InheritanceSpecs::Dad, InheritanceSpecs::Son].each(&:clear_blueprints!) + end + + it 'inherits blueprinted attributes from the parent class' do + InheritanceSpecs::Dad.blueprint do + name { 'Fred' } + end + InheritanceSpecs::Son.blueprint {} + expect(InheritanceSpecs::Son.make.name).to eq('Fred') + end + + it 'overrides blueprinted attributes in the child class' do + InheritanceSpecs::Dad.blueprint do + name { 'Fred' } + end + InheritanceSpecs::Son.blueprint do + name { 'George' } + end + expect(InheritanceSpecs::Dad.make.name).to eq('Fred') + expect(InheritanceSpecs::Son.make.name).to eq('George') + end + + it 'inherits from blueprinted attributes in ancestor class' do + InheritanceSpecs::Grandpa.blueprint do + name { 'Fred' } + end + InheritanceSpecs::Son.blueprint {} + expect(InheritanceSpecs::Grandpa.make.name).to eq('Fred') + expect { InheritanceSpecs::Dad.make }.to raise_error(RuntimeError) + expect(InheritanceSpecs::Son.make.name).to eq('Fred') + end + + it 'follows inheritance for named blueprints correctly' do + InheritanceSpecs::Dad.blueprint do + name { 'John' } + age { 56 } + end + InheritanceSpecs::Dad.blueprint(:special) do + name { 'Paul' } + end + InheritanceSpecs::Son.blueprint(:special) do + age { 37 } + end + expect(InheritanceSpecs::Son.make(:special).name).to eq('John') + expect(InheritanceSpecs::Son.make(:special).age).to eq(37) + end + end +end diff --git a/spec/machinist/blueprint_spec.rb b/spec/machinist/blueprint_spec.rb new file mode 100755 index 0000000..6872360 --- /dev/null +++ b/spec/machinist/blueprint_spec.rb @@ -0,0 +1,76 @@ +require 'ostruct' + +RSpec.describe Machinist::Blueprint do + it 'makes an object of the given class' do + blueprint = described_class.new(OpenStruct) {} + expect(blueprint.make).to be_an(OpenStruct) + end + + it 'constructs an attribute from the blueprint' do + blueprint = described_class.new(OpenStruct) do + name { 'Fred' } + end + expect(blueprint.make.name).to eq('Fred') + end + + it 'constructs an array for an attribute in the blueprint' do + blueprint = described_class.new(OpenStruct) do + things(3) { Object.new } + end + things = blueprint.make.things + expect(things).to be_an(Array) + expect(things.size).to eq(3) + things.each { |thing| expect(thing).to be_an(Object) } + expect(things.uniq).to eq(things) + end + + it 'allows passing in attributes to override the blueprint' do + block_called = false + blueprint = described_class.new(OpenStruct) do + name do + block_called = true + 'Fred' + end + end + expect(blueprint.make(name: 'Bill').name).to eq('Bill') + expect(block_called).to be_falsey + end + + it 'provides a serial number within the blueprint' do + blueprint = described_class.new(OpenStruct) do + name { "Fred #{sn}" } + end + expect(blueprint.make.name).to eq('Fred 0001') + expect(blueprint.make.name).to eq('Fred 0002') + end + + it 'provides access to the object being constructed within the blueprint' do + blueprint = described_class.new(OpenStruct) do + title { 'Test' } + body { object.title } + end + expect(blueprint.make.body).to eq('Test') + end + + it 'allows attribute names to be strings' do + blueprint = described_class.new(OpenStruct) do + name { 'Fred' } + end + expect(blueprint.make('name' => 'Bill').name).to eq('Bill') + end + + # These are normally a problem because of name clashes with the standard (but + # deprecated) Ruby methods. This test makes sure we work around this. + it 'works with type and id attributes' do + klass = Class.new do + attr_accessor :id, :type + end + blueprint = described_class.new(klass) do + id { 'custom id' } + type { 'custom type' } + end + object = blueprint.make + expect(object.id).to eq('custom id') + expect(object.type).to eq('custom type') + end +end diff --git a/spec/machinist/exceptions_spec.rb b/spec/machinist/exceptions_spec.rb new file mode 100755 index 0000000..a3dc783 --- /dev/null +++ b/spec/machinist/exceptions_spec.rb @@ -0,0 +1,16 @@ +RSpec.describe Machinist, 'exceptions' do + describe Machinist::BlueprintCantSaveError do + it 'presents the right message' do + blueprint = Machinist::Blueprint.new(String) {} + exception = Machinist::BlueprintCantSaveError.new(blueprint) + expect(exception.message).to eq('make! is not supported by blueprints for class String') + end + end + + describe Machinist::NoBlueprintError do + it 'presents the right message' do + exception = Machinist::NoBlueprintError.new(String, :master) + expect(exception.message).to eq('No master blueprint defined for class String') + end + end +end diff --git a/spec/machinist/machinable_spec.rb b/spec/machinist/machinable_spec.rb new file mode 100755 index 0000000..ddd29e4 --- /dev/null +++ b/spec/machinist/machinable_spec.rb @@ -0,0 +1,91 @@ +module MachinableSpecs + class Post + extend Machinist::Machinable + attr_accessor :title, :body, :comments + end + + class Comment + extend Machinist::Machinable + attr_accessor :post, :title + end +end + +RSpec.describe Machinist::Machinable do + before do + MachinableSpecs::Post.clear_blueprints! + end + + it 'makes an object' do + MachinableSpecs::Post.blueprint do + title { 'First Post' } + end + + post = MachinableSpecs::Post.make + expect(post).to be_a(MachinableSpecs::Post) + expect(post.title).to eq('First Post') + end + + it 'makes an object from a named blueprint' do + MachinableSpecs::Post.blueprint do + title { 'First Post' } + body { 'Woot!' } + end + + MachinableSpecs::Post.blueprint(:extra) do + title { 'Extra!' } + end + + post = MachinableSpecs::Post.make(:extra) + expect(post).to be_a(MachinableSpecs::Post) + expect(post.title).to eq('Extra!') + expect(post.body).to eq('Woot!') + end + + it 'makes an array of objects' do + MachinableSpecs::Post.blueprint do + title { 'First Post' } + end + + posts = MachinableSpecs::Post.make(3) + expect(posts).to be_an(Array) + expect(posts.size).to eq(3) + posts.each do |post| + expect(post).to be_a(MachinableSpecs::Post) + expect(post.title).to eq('First Post') + end + end + + it 'makes array attributes from the blueprint' do + MachinableSpecs::Comment.blueprint {} + MachinableSpecs::Post.blueprint do + comments(3) { MachinableSpecs::Comment.make } + end + + post = MachinableSpecs::Post.make + expect(post.comments).to be_a(Array) + expect(post.comments.size).to eq(3) + post.comments.each do |comment| + expect(comment).to be_a(MachinableSpecs::Comment) + end + end + + it 'fails without a blueprint' do + expect { MachinableSpecs::Post.make }.to raise_error(Machinist::NoBlueprintError) do |exception| + expect(exception.klass).to eq(MachinableSpecs::Post) + expect(exception.name).to eq(:master) + end + + expect { MachinableSpecs::Post.make(:some_name) }.to raise_error(Machinist::NoBlueprintError) do |exception| + expect(exception.klass).to eq(MachinableSpecs::Post) + expect(exception.name).to eq(:some_name) + end + end + + it 'fails when calling make! on an unsavable object' do + MachinableSpecs::Post.blueprint {} + + expect { MachinableSpecs::Post.make! }.to raise_error(Machinist::BlueprintCantSaveError) do |exception| + expect(exception.blueprint.klass).to eq(MachinableSpecs::Post) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb old mode 100644 new mode 100755 index 67626b4..30790be --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,110 @@ -$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' -$LOAD_PATH.unshift File.dirname(__FILE__) +# Configure Simplecov and Coveralls +unless ENV['NO_SIMPLECOV'] + require 'simplecov' + require 'coveralls' + + SimpleCov.start { add_filter '/spec/' } + Coveralls.wear! if ENV['COVERALLS_REPO_TOKEN'] +end -require 'rubygems' -require 'test/unit' -require 'rspec' require 'machinist' + +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = 'tmp/rspec/examples.txt' + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +end diff --git a/spec/support/active_record_environment.rb b/spec/support/active_record_environment.rb index 932231f..f620849 100644 --- a/spec/support/active_record_environment.rb +++ b/spec/support/active_record_environment.rb @@ -2,32 +2,32 @@ require 'machinist/active_record' ActiveRecord::Base.establish_connection( - :adapter => "sqlite3", - :database => ":memory:", - :timeout => 500 + adapter: 'sqlite3', + database: ':memory:', + timeout: 500 ) -ActiveRecord::Schema.define(:version => 0) do - create_table :users, :force => true do |t| +ActiveRecord::Schema.define(version: 0) do + create_table :users, force: true do |t| t.column :username, :string end - create_table :posts, :force => true do |t| + create_table :posts, force: true do |t| t.column :title, :string t.column :author_id, :integer t.column :body, :text end - create_table :comments, :force => true do |t| + create_table :comments, force: true do |t| t.column :post_id, :integer t.column :body, :text end - create_table :tags, :force => true do |t| + create_table :tags, force: true do |t| t.column :name, :string end - create_table :posts_tags, :id => false, :force => true do |t| + create_table :posts_tags, id: false, force: true do |t| t.column :post_id, :integer t.column :tag_id, :integer end @@ -40,7 +40,7 @@ class User < ActiveRecord::Base class Post < ActiveRecord::Base has_many :comments - belongs_to :author, :class_name => "User" + belongs_to :author, class_name: 'User' has_and_belongs_to_many :tags end @@ -53,12 +53,10 @@ class Tag < ActiveRecord::Base end module ActiveRecordEnvironment - def empty_database! [User, Post, Comment].each do |klass| klass.delete_all klass.clear_blueprints! end end - end