DEV: add rubocop rules

DEV: add rubocop rules

This follows up on #11 and introduces Discourse rubocop

It also has some positive minor perf improvements due to frozen strings

diff --git a/.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml b/.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
new file mode 100644
index 0000000..0a15cd9
--- /dev/null
+++ b/.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
@@ -0,0 +1,151 @@
+require:
+  - rubocop-discourse
+
+AllCops:
+  TargetRubyVersion: 2.4
+  DisabledByDefault: true
+  Exclude:
+    - "db/schema.rb"
+    - "bundle/**/*"
+    - "vendor/**/*"
+    - "node_modules/**/*"
+    - "public/**/*"
+    - "plugins/**/gems/**/*"
+
+# Prefer &&/|| over and/or.
+Style/AndOr:
+  Enabled: true
+
+Style/FrozenStringLiteralComment:
+  Enabled: true
+
+# Do not use braces for hash literals when they are the last argument of a
+# method call.
+Style/BracesAroundHashParameters:
+  Enabled: true
+
+# Align `when` with `case`.
+Layout/CaseIndentation:
+  Enabled: true
+
+# Align comments with method definitions.
+Layout/CommentIndentation:
+  Enabled: true
+
+# No extra empty lines.
+Layout/EmptyLines:
+  Enabled: true
+
+# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
+Style/HashSyntax:
+  Enabled: true
+
+# Two spaces, no tabs (for indentation).
+Layout/IndentationWidth:
+  Enabled: true
+
+Layout/SpaceAfterColon:
+  Enabled: true
+
+Layout/SpaceAfterComma:
+  Enabled: true
+
+Layout/SpaceAroundEqualsInParameterDefault:
+  Enabled: true
+
+Layout/SpaceAroundKeyword:
+  Enabled: true
+
+Layout/SpaceAroundOperators:
+  Enabled: true
+
+Layout/SpaceBeforeFirstArg:
+  Enabled: true
+
+# Defining a method with parameters needs parentheses.
+Style/MethodDefParentheses:
+  Enabled: true
+
+# Use `foo {}` not `foo{}`.
+Layout/SpaceBeforeBlockBraces:
+  Enabled: true
+
+# Use `foo { bar }` not `foo {bar}`.
+Layout/SpaceInsideBlockBraces:
+  Enabled: true
+
+# Use `{ a: 1 }` not `{a:1}`.
+Layout/SpaceInsideHashLiteralBraces:
+  Enabled: true
+
+Layout/SpaceInsideParens:
+  Enabled: true
+
+# Detect hard tabs, no hard tabs.
+Layout/Tab:
+  Enabled: true
+
+# Blank lines should not have any spaces.
+Layout/TrailingEmptyLines:
+  Enabled: true
+
+# No trailing whitespace.
+Layout/TrailingWhitespace:
+  Enabled: true
+
+Lint/Debugger:
+  Enabled: true
+
+Layout/BlockAlignment:
+  Enabled: true
+
+# Align `end` with the matching keyword or starting expression except for
+# assignments, where it should be aligned with the LHS.
+Layout/EndAlignment:
+  Enabled: true
+  EnforcedStyleAlignWith: variable
+
+# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
+Lint/RequireParentheses:
+  Enabled: true
+
+Lint/ShadowingOuterLocalVariable:
+  Enabled: true
+
+Layout/MultilineMethodCallIndentation:
+  Enabled: true
+  EnforcedStyle: indented
+
+Layout/HashAlignment:
+  Enabled: true
+
+Bundler/OrderedGems:
+  Enabled: false
+
+Style/SingleLineMethods:
+  Enabled: true
+
+Style/Semicolon:
+  Enabled: true
+  AllowAsExpressionSeparator: true
+
+Style/RedundantReturn:
+  Enabled: true
+
+DiscourseCops/NoChdir:
+  Enabled: true
+  Exclude:
+    - 'spec/**/*' # Specs are run sequentially, so chdir can be used
+    - 'plugins/*/spec/**/*'
+
+DiscourseCops/NoURIEscapeEncode:
+  Enabled: true
+
+Style/GlobalVars:
+  Enabled: true
+  Severity: warning
+  Exclude:
+    - 'lib/tasks/**/*'
+    - 'script/**/*'
+    - 'spec/**/*.rb'
+    - 'plugins/*/spec/**/*'
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..a3f680f
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,5 @@
+inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
+
+AllCops:
+  Exclude:
+    - 'bench/**/*'
diff --git a/.travis.yml b/.travis.yml
index 9d75b49..f0483ce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,8 @@
 language: ruby
 rvm:
-  - 2.5.1
+  - 2.5
+  - 2.6
+  - 2.7
   - ruby-head
 
 before_install:
diff --git a/Gemfile b/Gemfile
index 1b116c2..554e8a1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,8 @@
+# frozen_string_literal: true
+
 source "https://rubygems.org"
 
-git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
+git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
 
 # Specify your gem's dependencies in mini_sql.gemspec
 gemspec
diff --git a/Guardfile b/Guardfile
index 1483d2b..ff1ed06 100644
--- a/Guardfile
+++ b/Guardfile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 guard :minitest do
   watch(%r{^test/(.*)_test\.rb$})
   watch(%r{^lib/(.*/)?([^/]+)\.rb$})     { |m| "test/#{m[1]}#{m[2]}_test.rb" }
diff --git a/Rakefile b/Rakefile
index c3359c1..dbefe50 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require "bundler/gem_tasks"
 require "rake/testtask"
 
@@ -13,4 +15,4 @@ Rake::TestTask.new(:test) do |t|
   t.test_files = FileList[test_glob]
 end
 
-task :default => :test
+task default: :test
diff --git a/bench/timestamp_perf.rb b/bench/timestamp_perf.rb
index 10d1cd5..8349592 100644
--- a/bench/timestamp_perf.rb
+++ b/bench/timestamp_perf.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'bundler/inline'
 
 gemfile do
@@ -21,8 +23,8 @@ require 'benchmark/ips'
 require 'mini_sql'
 
 ActiveRecord::Base.establish_connection(
-  :adapter => "postgresql",
-  :database => "test_db"
+  adapter: "postgresql",
+  database: "test_db"
 )
 
 Sequel.default_timezone = :utc
@@ -47,20 +49,20 @@ SQL
 class Timestamp < ActiveRecord::Base
 end
 
-class TimestampSequel< Sequel::Model(:timestamps)
+class TimestampSequel < Sequel::Model(:timestamps)
 end
 
-
 Timestamp.transaction do
   stamps = {
   }
   Timestamp.columns.each do |c|
-    stamps[c.name.to_sym] = case c.type
-                           when :integer then 1
-                           when :datetime then Time.now
-                           when :boolean then false
-                           else "HELLO WORLD" * 2
-                           end
+    stamps[c.name.to_sym] =
+      case c.type
+      when :integer then 1
+      when :datetime then Time.now
+      when :boolean then false
+      else "HELLO WORLD" * 2
+      end
   end
 
   1000.times do |id|
@@ -71,7 +73,7 @@ end
 
 $conn = ActiveRecord::Base.connection.raw_connection
 
-def ar_pluck_times(l=1000)
+def ar_pluck_times(l = 1000)
   s = +""
   Timestamp.limit(l).order(:id).pluck(:time1, :time2).each do |time1, time2|
     s << time1.to_f.to_s
@@ -80,7 +82,7 @@ def ar_pluck_times(l=1000)
   s
 end
 
-def ar_select_times(l=1000)
+def ar_select_times(l = 1000)
   s = +""
   Timestamp.limit(l).order(:id).select(:time1, :time2).each do |t|
     s << t.time1.to_f.to_s
@@ -91,7 +93,7 @@ end
 
 $mini_sql = MiniSql::Connection.new($conn)
 
-def pg_times_params(l=1000)
+def pg_times_params(l = 1000)
   s = +""
   # use the safe pattern here
   r = $conn.async_exec_params(-"select time1, time2 from timestamps order by id limit $1", [l])
@@ -110,7 +112,7 @@ def pg_times_params(l=1000)
   s
 end
 
-def pg_times(l=1000)
+def pg_times(l = 1000)
   s = +""
   # use the safe pattern here
   r = $conn.async_exec("select time1, time2 from timestamps order by id limit #{l}")
@@ -129,7 +131,7 @@ def pg_times(l=1000)
   s
 end
 
-def mini_sql_times(l=1000)
+def mini_sql_times(l = 1000)
   s = +""
   $mini_sql.query(-"select time1, time2 from timestamps order by id limit ?", l).each do |t|
     s << t.time1.to_f.to_s
@@ -138,7 +140,7 @@ def mini_sql_times(l=1000)
   s
 end
 
-def sequel_times(l=1000)
+def sequel_times(l = 1000)
   s = +""
   TimestampSequel.limit(l).order(:id).select(:time1, :time2).each do |t|
     s << t.time1.to_f.to_s
@@ -147,7 +149,7 @@ def sequel_times(l=1000)
   s
 end
 
-def sequel_pluck_times(l=1000)
+def sequel_pluck_times(l = 1000)
   s = +""
   TimestampSequel.limit(l).order(:id).select_map([:time1, :time2]).each do |t|
     s << t[0].to_f.to_s
@@ -156,7 +158,7 @@ def sequel_pluck_times(l=1000)
   s
 end
 
-def sequel_raw_times(l=1000)
+def sequel_raw_times(l = 1000)
   s = +""

[... diff too long, it was truncated ...]

GitHub sha: 4a940a5d