diff --git a/.hound.yml b/.hound.yml index 93756dce..f534df8c 100644 --- a/.hound.yml +++ b/.hound.yml @@ -1,4 +1,2 @@ -DotPosition: - EnforcedStyle: leading -Style/AlignParameters: - EnforcedStyle: with_fixed_indentation +rubocop: + config_file: .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..2447a73d --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,129 @@ +AllCops: + TargetRubyVersion: 2.3.0 + Exclude: + - "tmp/**/*" + - "bin/*" + - "spec/dummy/**/*" + +Bundler/OrderedGems: + Enabled: false + +Gemspec/OrderedDependencies: + Enabled: false + +Layout/AlignParameters: + Enabled: true + EnforcedStyle: with_fixed_indentation +Layout/ConditionPosition: + Enabled: false +Layout/DotPosition: + EnforcedStyle: leading +Layout/ExtraSpacing: + Enabled: true +Layout/IndentAssignment: + Enabled: False +Layout/MultilineOperationIndentation: + Enabled: true + EnforcedStyle: indented +Layout/MultilineMethodCallIndentation: + Enabled: true + EnforcedStyle: indented + +Lint/AmbiguousOperator: + Enabled: true +Lint/AmbiguousRegexpLiteral: + Enabled: true +Lint/DuplicatedKey: + Enabled: true + +Metrics/ClassLength: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/AbcSize: + Enabled: false +Metrics/BlockLength: + CountComments: true # count full line comments? + Max: 25 + ExcludedMethods: [] + Exclude: + - "spec/**/*" + - "*.gemspec" +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/LineLength: + Max: 80 +Metrics/MethodLength: + Enabled: false + +Security/Eval: + Enabled: true + Exclude: + - "spec/scenic/schema_dumper_spec.rb" +Style/BlockDelimiters: + Enabled: false +Style/CollectionMethods: + Enabled: true + PreferredMethods: + find: find + inject: reduce + collect: map + find_all: select +Style/ConditionalAssignment: + Enabled: false +Style/ClassAndModuleChildren: + Enabled: true + Exclude: + - "spec/**/*" +Style/Documentation: + Enabled: false +Style/FrozenStringLiteralComment: + Description: >- + Add the frozen_string_literal comment to the top of files + to help transition from Ruby 2.3.0 to Ruby 3.0. + Enabled: false +Style/GuardClause: + Enabled: false +Style/IfUnlessModifier: + Enabled: false +Style/Lambda: + Enabled: false +Style/NumericLiterals: + Enabled: false +Style/OneLineConditional: + Enabled: false +Style/PercentLiteralDelimiters: + Enabled: false +Style/StringLiterals: + EnforcedStyle: double_quotes + Enabled: true +Style/TrailingCommaInArguments: + Description: 'Checks for trailing comma in argument lists.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' + EnforcedStyleForMultiline: comma + SupportedStylesForMultiline: + - comma + - consistent_comma + - no_comma + Enabled: true +Style/TrailingCommaInArrayLiteral: + Description: 'Checks for trailing comma in array literals.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' + EnforcedStyleForMultiline: comma + SupportedStylesForMultiline: + - comma + - consistent_comma + - no_comma + Enabled: true +Style/TrailingCommaInHashLiteral: + Description: 'Checks for trailing comma in hash literals.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' + EnforcedStyleForMultiline: comma + SupportedStylesForMultiline: + - comma + - consistent_comma + - no_comma + Enabled: true +Style/WordArray: + Enabled: false + diff --git a/Gemfile b/Gemfile index 9e82697a..9bb0840c 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source 'https://rubygems.org' +source "https://rubygems.org" # Specify your gem's dependencies in scenic.gemspec gemspec diff --git a/Rakefile b/Rakefile index 96fe6adc..91805257 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ -require 'bundler/gem_tasks' -require 'rspec/core/rake_task' +require "bundler/gem_tasks" +require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) diff --git a/lib/generators/scenic/model/model_generator.rb b/lib/generators/scenic/model/model_generator.rb index 3b2018d6..b04e4186 100644 --- a/lib/generators/scenic/model/model_generator.rb +++ b/lib/generators/scenic/model/model_generator.rb @@ -8,7 +8,7 @@ module Generators # @api private class ModelGenerator < Rails::Generators::NamedBase include Scenic::Generators::Materializable - source_root File.expand_path("../templates", __FILE__) + source_root File.expand_path("templates", __dir__) def invoke_rails_model_generator invoke "model", @@ -35,7 +35,7 @@ def invoke_view_generator def evaluate_template(source) source = File.expand_path(find_in_source_paths(source.to_s)) - context = instance_eval("binding") + context = instance_eval("binding", __FILE__, __LINE__) ERB.new( ::File.binread(source), nil, diff --git a/lib/generators/scenic/view/view_generator.rb b/lib/generators/scenic/view/view_generator.rb index df25923d..7b70a560 100644 --- a/lib/generators/scenic/view/view_generator.rb +++ b/lib/generators/scenic/view/view_generator.rb @@ -8,7 +8,7 @@ module Generators class ViewGenerator < Rails::Generators::NamedBase include Rails::Generators::Migration include Scenic::Generators::Materializable - source_root File.expand_path("../templates", __FILE__) + source_root File.expand_path("templates", __dir__) def create_views_directory unless views_directory_path.exist? @@ -56,7 +56,7 @@ def version def migration_class_name if creating_new_view? - "Create#{class_name.gsub('.', '').pluralize}" + "Create#{class_name.tr('.', '').pluralize}" else "Update#{class_name.pluralize}ToVersion#{version}" end @@ -74,7 +74,7 @@ def activerecord_migration_class private def views_directory_path - @views_directory_path ||= Rails.root.join(*%w(db views)) + @views_directory_path ||= Rails.root.join("db", "views") end def version_regex @@ -82,7 +82,7 @@ def version_regex end def creating_new_view? - previous_version == 0 + previous_version.zero? end def definition @@ -94,7 +94,7 @@ def previous_definition end def plural_file_name - @plural_file_name ||= file_name.pluralize.gsub(".", "_") + @plural_file_name ||= file_name.pluralize.tr(".", "_") end def destroying? @@ -110,8 +110,11 @@ def formatted_plural_name end def create_view_options - return "" unless materialized? - ", materialized: #{no_data? ? '{ no_data: true }' : true}" + if materialized? + ", materialized: #{no_data? ? '{ no_data: true }' : true}" + else + "" + end end def destroying_initial_view? diff --git a/lib/scenic/adapters/postgres/refresh_dependencies.rb b/lib/scenic/adapters/postgres/refresh_dependencies.rb index 28874b18..e5dbd6c8 100644 --- a/lib/scenic/adapters/postgres/refresh_dependencies.rb +++ b/lib/scenic/adapters/postgres/refresh_dependencies.rb @@ -46,11 +46,16 @@ def initialize(raw_dependencies, view_to_refresh) def to_sorted_array dependency_hash = parse_to_hash(raw_dependencies) sorted_arr = tsort(dependency_hash) + idx = sorted_arr.find_index do |dep| dep.include?(view_to_refresh.to_s) end - return [] if idx.nil? - sorted_arr[0...idx] + + if idx.present? + sorted_arr[0...idx] + else + [] + end end private diff --git a/lib/scenic/adapters/postgres/views.rb b/lib/scenic/adapters/postgres/views.rb index b995d044..fc55e9d6 100644 --- a/lib/scenic/adapters/postgres/views.rb +++ b/lib/scenic/adapters/postgres/views.rb @@ -57,6 +57,7 @@ def to_scenic_view(result) def pg_identifier(name) return name if name =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/ + pgconn.quote_ident(name) end diff --git a/lib/scenic/schema_dumper.rb b/lib/scenic/schema_dumper.rb index 6b72d201..68aab1b2 100644 --- a/lib/scenic/schema_dumper.rb +++ b/lib/scenic/schema_dumper.rb @@ -32,8 +32,8 @@ def dumpable_views_in_database def ignored?(table_name) ["schema_migrations", ignore_tables].flatten.any? do |ignored| case ignored - when String; remove_prefix_and_suffix(table_name) == ignored - when Regexp; remove_prefix_and_suffix(table_name) =~ ignored + when String then remove_prefix_and_suffix(table_name) == ignored + when Regexp then remove_prefix_and_suffix(table_name) =~ ignored else raise StandardError, "ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values." end diff --git a/lib/scenic/statements.rb b/lib/scenic/statements.rb index c1a9a5dd..84bf24b0 100644 --- a/lib/scenic/statements.rb +++ b/lib/scenic/statements.rb @@ -153,8 +153,11 @@ def definition(name, version) end def no_data(materialized) - return false unless materialized.is_a? Hash - materialized.fetch(:no_data, false) + if materialized.is_a?(Hash) + materialized.fetch(:no_data, false) + else + false + end end end end diff --git a/scenic.gemspec b/scenic.gemspec index 6d5dc8aa..40f0d1ea 100644 --- a/scenic.gemspec +++ b/scenic.gemspec @@ -1,38 +1,37 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'scenic/version' +require "scenic/version" Gem::Specification.new do |spec| - spec.name = 'scenic' + spec.name = "scenic" spec.version = Scenic::VERSION - spec.authors = ['Derek Prior', 'Caleb Thompson'] - spec.email = ['derekprior@gmail.com', 'caleb@calebthompson.io'] - spec.summary = %q{Support for database views in Rails migrations} + spec.authors = ["Derek Prior", "Caleb Thompson"] + spec.email = ["derekprior@gmail.com", "caleb@calebthompson.io"] + spec.summary = "Support for database views in Rails migrations" spec.description = <<-DESCRIPTION Adds methods to ActiveRecord::Migration to create and manage database views in Rails DESCRIPTION - spec.homepage = 'https://github.com/scenic-views/scenic' - spec.license = 'MIT' + spec.homepage = "https://github.com/scenic-views/scenic" + spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0") spec.test_files = spec.files.grep(%r{^spec/}) - spec.require_paths = ['lib'] + spec.require_paths = ["lib"] - spec.add_development_dependency 'appraisal' - spec.add_development_dependency 'bundler', '>= 1.5' - spec.add_development_dependency 'database_cleaner' - spec.add_development_dependency 'rake' - spec.add_development_dependency 'rspec', '>= 3.3' - spec.add_development_dependency 'pg', '~> 0.19' - spec.add_development_dependency 'pry' - spec.add_development_dependency 'ammeter', '>= 1.1.3' - spec.add_development_dependency 'yard' - spec.add_development_dependency 'redcarpet' + spec.add_development_dependency "appraisal" + spec.add_development_dependency "bundler", ">= 1.5" + spec.add_development_dependency "database_cleaner" + spec.add_development_dependency "rake" + spec.add_development_dependency "rspec", ">= 3.3" + spec.add_development_dependency "pg", "~> 0.19" + spec.add_development_dependency "pry" + spec.add_development_dependency "ammeter", ">= 1.1.3" + spec.add_development_dependency "yard" + spec.add_development_dependency "redcarpet" - spec.add_dependency 'activerecord', '>= 4.0.0' - spec.add_dependency 'railties', '>= 4.0.0' + spec.add_dependency "activerecord", ">= 4.0.0" + spec.add_dependency "railties", ">= 4.0.0" - spec.required_ruby_version = '>= 2.3.0' + spec.required_ruby_version = ">= 2.3.0" end diff --git a/spec/acceptance/user_manages_views_spec.rb b/spec/acceptance/user_manages_views_spec.rb index 979fcf5e..426e9220 100644 --- a/spec/acceptance/user_manages_views_spec.rb +++ b/spec/acceptance/user_manages_views_spec.rb @@ -1,4 +1,5 @@ require "acceptance_helper" +require "English" describe "User manages views" do it "handles simple views" do @@ -56,7 +57,7 @@ def successfully(command) `RAILS_ENV=test #{command}` - expect($?.exitstatus).to eq(0), "'#{command}' was unsuccessful" + expect($CHILD_STATUS.exitstatus).to eq(0), "'#{command}' was unsuccessful" end def write_definition(file, contents) diff --git a/spec/generators/scenic/model/model_generator_spec.rb b/spec/generators/scenic/model/model_generator_spec.rb index 751948a5..1b185cb9 100644 --- a/spec/generators/scenic/model/model_generator_spec.rb +++ b/spec/generators/scenic/model/model_generator_spec.rb @@ -6,7 +6,7 @@ module Scenic::Generators before do allow(ViewGenerator).to receive(:new) .and_return( - instance_double("Scenic::Generators::ViewGenerator").as_null_object + instance_double("Scenic::Generators::ViewGenerator").as_null_object, ) end diff --git a/spec/generators/scenic/view/view_generator_spec.rb b/spec/generators/scenic/view/view_generator_spec.rb index f39767cd..e85b74c5 100644 --- a/spec/generators/scenic/view/view_generator_spec.rb +++ b/spec/generators/scenic/view/view_generator_spec.rb @@ -31,7 +31,7 @@ run_generator ["aired_episode", "--materialized"] migration = migration_file( - "db/migrate/update_aired_episodes_to_version_2.rb" + "db/migrate/update_aired_episodes_to_version_2.rb", ) expect(migration).to contain "materialized: true" end diff --git a/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb b/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb index 2cc8e8ac..d1c77716 100644 --- a/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb +++ b/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb @@ -26,14 +26,14 @@ module Adapters "SELECT * from third", ) - expect(adapter).to receive(:refresh_materialized_view). - with("public.first").ordered + expect(adapter).to receive(:refresh_materialized_view) + .with("public.first").ordered - expect(adapter).to receive(:refresh_materialized_view). - with("public.second").ordered + expect(adapter).to receive(:refresh_materialized_view) + .with("public.second").ordered - expect(adapter).to receive(:refresh_materialized_view). - with("public.third").ordered + expect(adapter).to receive(:refresh_materialized_view) + .with("public.third").ordered described_class.call(:fourth, adapter, ActiveRecord::Base.connection) end diff --git a/spec/scenic/adapters/postgres_spec.rb b/spec/scenic/adapters/postgres_spec.rb index 7d1b4643..2d973730 100644 --- a/spec/scenic/adapters/postgres_spec.rb +++ b/spec/scenic/adapters/postgres_spec.rb @@ -104,8 +104,8 @@ module Adapters connection = double("Connection").as_null_object connectable = double("Connectable", connection: connection) adapter = Postgres.new(connectable) - expect(Scenic::Adapters::Postgres::RefreshDependencies). - to receive(:call).with(:tests, adapter, connection) + expect(Scenic::Adapters::Postgres::RefreshDependencies) + .to receive(:call).with(:tests, adapter, connection) adapter.refresh_materialized_view(:tests, cascade: true) end diff --git a/spec/scenic/definition_spec.rb b/spec/scenic/definition_spec.rb index ac39f517..ff9835b8 100644 --- a/spec/scenic/definition_spec.rb +++ b/spec/scenic/definition_spec.rb @@ -22,7 +22,7 @@ module Scenic end describe "path" do - it "returns a sql file in db/views with padded version and view name" do + it "returns a sql file in db/views with padded version and view name" do expected = "db/views/searches_v01.sql" definition = Definition.new("searches", 1) diff --git a/spec/scenic/schema_dumper_spec.rb b/spec/scenic/schema_dumper_spec.rb index e8140e52..87e683b7 100644 --- a/spec/scenic/schema_dumper_spec.rb +++ b/spec/scenic/schema_dumper_spec.rb @@ -93,7 +93,8 @@ class SearchInAHaystack < ActiveRecord::Base it "dumps a create_view for a view in the database" do view_definition = "SELECT 'needle'::text AS haystack" Search.connection.execute( - "CREATE SCHEMA scenic; SET search_path TO scenic, public") + "CREATE SCHEMA scenic; SET search_path TO scenic, public", + ) Search.connection.create_view 'scenic."search in a haystack"', sql_definition: view_definition stream = StringIO.new diff --git a/spec/scenic/statements_spec.rb b/spec/scenic/statements_spec.rb index 487232a9..2b9764c3 100644 --- a/spec/scenic/statements_spec.rb +++ b/spec/scenic/statements_spec.rb @@ -33,14 +33,14 @@ module Scenic it "creates version 1 of the view if neither version nor sql_defintion are provided" do version = 1 definition_stub = instance_double("Definition", to_sql: "foo") - allow(Definition).to receive(:new). - with(:views, version). - and_return(definition_stub) + allow(Definition).to receive(:new) + .with(:views, version) + .and_return(definition_stub) connection.create_view :views - expect(Scenic.database).to have_received(:create_view). - with(:views, definition_stub.to_sql) + expect(Scenic.database).to have_received(:create_view) + .with(:views, definition_stub.to_sql) end it "raises an error if both version and sql_defintion are provided" do @@ -57,8 +57,8 @@ module Scenic connection.create_view(:views, version: 1, materialized: true) - expect(Scenic.database).to have_received(:create_materialized_view). - with(:views, definition.to_sql, no_data: false) + expect(Scenic.database).to have_received(:create_materialized_view) + .with(:views, definition.to_sql, no_data: false) end end @@ -73,8 +73,8 @@ module Scenic materialized: { no_data: true }, ) - expect(Scenic.database).to have_received(:create_materialized_view). - with(:views, definition.to_sql, no_data: true) + expect(Scenic.database).to have_received(:create_materialized_view) + .with(:views, definition.to_sql, no_data: true) end end @@ -112,8 +112,8 @@ module Scenic connection.update_view(:name, sql_definition: sql_definition) - expect(Scenic.database).to have_received(:update_view). - with(:name, sql_definition) + expect(Scenic.database).to have_received(:update_view) + .with(:name, sql_definition) end it "updates the materialized view in the database" do @@ -124,15 +124,15 @@ module Scenic connection.update_view(:name, version: 3, materialized: true) - expect(Scenic.database).to have_received(:update_materialized_view). - with(:name, definition.to_sql, no_data: false) + expect(Scenic.database).to have_received(:update_materialized_view) + .with(:name, definition.to_sql, no_data: false) end it "updates the materialized view in the database with NO DATA" do definition = instance_double("Definition", to_sql: "definition") - allow(Definition).to receive(:new). - with(:name, 3). - and_return(definition) + allow(Definition).to receive(:new) + .with(:name, 3) + .and_return(definition) connection.update_view( :name, @@ -140,14 +140,15 @@ module Scenic materialized: { no_data: true }, ) - expect(Scenic.database).to have_received(:update_materialized_view). - with(:name, definition.to_sql, no_data: true) + expect(Scenic.database).to have_received(:update_materialized_view) + .with(:name, definition.to_sql, no_data: true) end it "raises an error if not supplied a version or sql_defintion" do expect { connection.update_view :views }.to raise_error( ArgumentError, - /sql_definition or version must be specified/) + /sql_definition or version must be specified/, + ) end it "raises an error if both version and sql_defintion are provided" do @@ -155,7 +156,8 @@ module Scenic connection.update_view( :views, version: 1, - sql_definition: "a defintion") + sql_definition: "a defintion", + ) end.to raise_error ArgumentError, /cannot both be set/ end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f949b011..6f401c3e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,7 @@ ENV["RAILS_ENV"] = "test" require "database_cleaner" -require File.expand_path("../dummy/config/environment", __FILE__) +require File.expand_path("dummy/config/environment", __dir__) require "support/generator_spec_setup" require "support/view_definition_helpers" diff --git a/spec/support/generator_spec_setup.rb b/spec/support/generator_spec_setup.rb index de2e5f1c..fdeaa9d1 100644 --- a/spec/support/generator_spec_setup.rb +++ b/spec/support/generator_spec_setup.rb @@ -5,7 +5,7 @@ RSpec.configure do |config| config.before(:example, :generator) do - fake_rails_root = File.expand_path("../../../tmp", __FILE__) + fake_rails_root = File.expand_path("../../tmp", __dir__) allow(Rails).to receive(:root).and_return(Pathname.new(fake_rails_root)) destination fake_rails_root