diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b8c6e60ed7364b96d7e29ddb141f41eedec89d3c..a0a9ab03f49755f1d629c2c0d59199d3751b76ba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -21,6 +21,13 @@ before_script:
     paths:
       - .gems
 
+.ruby_25: &ruby_25
+  image: registry.roqua.nl/roqua/docker-base-images:ruby-2.5
+  cache:
+    key: ruby_25
+    paths:
+      - .gems
+
 rails_42_ruby_23:
   <<: *ruby_23
   script:
@@ -36,6 +43,11 @@ rails_50_ruby_24:
   script:
     - bundle exec appraisal rails50 bundle exec rspec
 
+rails_50_ruby_25:
+  <<: *ruby_25
+  script:
+    - bundle exec appraisal rails50 bundle exec rspec
+
 rails_51_ruby_23:
   <<: *ruby_23
   script:
@@ -46,6 +58,11 @@ rails_51_ruby_24:
   script:
     - bundle exec appraisal rails51 bundle exec rspec
 
+rails_51_ruby_25:
+  <<: *ruby_25
+  script:
+    - bundle exec appraisal rails51 bundle exec rspec
+
 rails_52_ruby_23:
   <<: *ruby_23
   script:
@@ -55,3 +72,8 @@ rails_52_ruby_24:
   <<: *ruby_24
   script:
     - bundle exec appraisal rails52 bundle exec rspec
+
+rails_52_ruby_25:
+  <<: *ruby_25
+  script:
+    - bundle exec appraisal rails52 bundle exec rspec
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 849c230a6701410e45c23d7a2c25a3a26a0b2294..2a96838eb045794910501ae15616aee40fa9d63f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.3.0
+
+* Support for Ruby 2.5
+* Removed Fixnum#clamp, since Fixnum was deprecated and the clamp method was never used.
+
 ## 0.2.0
 
 * Removed Array#stable_sort_by, since it was not stable and the name was wrong.
diff --git a/Gemfile b/Gemfile
index deb8331e066cbede7df14f7bc1fe34a8c4d288e0..ad25f50ee86675ba121e607e6035fc32b901444a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,7 +9,7 @@ gem 'roqua_styleguide', git: 'https://gitlab.roqua.nl/roqua/styleguide.git'
 group :test do
   gem 'actionpack', '>= 4.0'
   gem 'active_interaction', '~> 3.0'
-  gem 'appsignal'
+  gem 'appsignal', '~> 2.9.6'
   gem 'climate_control' # For ENV modification in specs
   gem 'combustion', '~> 0.5.2'
   gem 'fakefs', require: 'fakefs/safe'
diff --git a/Gemfile.lock b/Gemfile.lock
index a321c6799d20a221abba7cd77572a587da8f3137..1f7b53e7dbd87bd041dfb498f506382df795a9d6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,7 +8,7 @@ GIT
 PATH
   remote: .
   specs:
-    roqua-support (0.1.33)
+    roqua-support (0.3.0)
       active_interaction (~> 3.0)
       activesupport (>= 3.2, < 6)
       naught (~> 1.0)
@@ -47,7 +47,7 @@ GEM
       bundler
       rake
       thor (>= 0.14.0)
-    appsignal (2.3.1)
+    appsignal (2.9.6)
       rack
     arel (7.1.4)
     ast (2.3.0)
@@ -181,7 +181,7 @@ DEPENDENCIES
   actionpack (>= 4.0)
   active_interaction (~> 3.0)
   appraisal
-  appsignal
+  appsignal (~> 2.9.6)
   bundler (~> 1.0)
   climate_control
   combustion (~> 0.5.2)
@@ -195,8 +195,8 @@ DEPENDENCIES
   rspec (>= 2.12.0, < 4.0)
   rspec-instrumentation-matcher
   rspec-rails
-  sqlite3
+  sqlite3 (~> 1.3.6)
   timecop
 
 BUNDLED WITH
-   1.16.4
+   1.16.6
diff --git a/lib/roqua-support/version.rb b/lib/roqua-support/version.rb
index 25a34a819efc8a05654b5e557942db785bbcdbbc..b1a181bf13fafa235c669e9e678ae8485d1e646f 100644
--- a/lib/roqua-support/version.rb
+++ b/lib/roqua-support/version.rb
@@ -1,5 +1,5 @@
 module Roqua
   module Support
-    VERSION = '0.2.0'.freeze
+    VERSION = '0.3.0'.freeze
   end
 end
diff --git a/lib/roqua/core_ext/fixnum/clamp.rb b/lib/roqua/core_ext/fixnum/clamp.rb
deleted file mode 100644
index f25971da57a996bfec7301fbb29ea32d079c1f81..0000000000000000000000000000000000000000
--- a/lib/roqua/core_ext/fixnum/clamp.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class Fixnum
-  def clamp(low, high)
-    raise "Low (#{low}) must be lower than high (#{high})" unless low < high
-    return low if self < low
-    return high if self > high
-    self
-  end
-end
\ No newline at end of file
diff --git a/lib/roqua/logging/roqua_logging_railtie.rb b/lib/roqua/logging/roqua_logging_railtie.rb
index 1d28c45cdff9d5fc24976d1c2c5bd53a7d565d68..6881646da9d31f823689525ec6488851ad5e80d4 100644
--- a/lib/roqua/logging/roqua_logging_railtie.rb
+++ b/lib/roqua/logging/roqua_logging_railtie.rb
@@ -1,4 +1,3 @@
-
 class RoquaLoggingRailtie < Rails::Railtie
   config.after_initialize do |app|
     RoquaLoggingRailtie.configure
diff --git a/lib/roqua/probes/base_probe.rb b/lib/roqua/probes/base_probe.rb
index 7ae1a35cceae6eb882d1ce610c3d21962d7e2c31..61411e5a38bca8fa3d6a12fc02407ac634cbd0e7 100644
--- a/lib/roqua/probes/base_probe.rb
+++ b/lib/roqua/probes/base_probe.rb
@@ -3,7 +3,8 @@ module Roqua
     module BaseProbe
       def enable
         new.tap do |probe|
-          Appsignal::Minutely.probes << probe unless Appsignal::Minutely.probes.map(&:class).include?(probe.class)
+          probe_sym = probe.class.to_s.to_sym
+          Appsignal::Minutely.probes.register(probe_sym, probe) unless Appsignal::Minutely.probes[probe_sym]
         end
       end
     end
diff --git a/lib/roqua/support.rb b/lib/roqua/support.rb
index 77f1c16ec0dc20422a53451e07a03093e519be3c..b4b5f52953173a4cf243c6c6404e74ded89c7a85 100644
--- a/lib/roqua/support.rb
+++ b/lib/roqua/support.rb
@@ -1,5 +1,5 @@
 require 'logger'
-require 'roqua/logging/roqua_logging_railtie'
+require 'roqua/logging/roqua_logging_railtie' if defined?(Rails)
 require 'roqua/support/instrumentation'
 require 'roqua/support/log_wrapper'
 require 'roqua/support/errors'
diff --git a/lib/roqua/support/errors.rb b/lib/roqua/support/errors.rb
index bb0c69d8d15eb0fc9cdb10acb650dec4c0c11cf2..d90b18f8023d507aba2b2e93c3977ef12500fdce 100644
--- a/lib/roqua/support/errors.rb
+++ b/lib/roqua/support/errors.rb
@@ -62,7 +62,6 @@ module Roqua
                               parameters: parameters}
             exception_info[:notification_urls] = notification_urls if notification_urls.present?
             exception_info[:backtrace] = exception.backtrace unless skip_backtrace
-            puts exception_info.inspect
             Roqua.logger.error('roqua.exception', exception_info)
           end
         rescue Exception
diff --git a/roqua-support.gemspec b/roqua-support.gemspec
index e3cf0b0c93f6ba46195fc901601b3e8b568f34a3..8e415282bca72fa0939e7cea1be29f20118de469 100644
--- a/roqua-support.gemspec
+++ b/roqua-support.gemspec
@@ -28,6 +28,6 @@ Gem::Specification.new do |gem|
   gem.add_development_dependency 'delayed_job_active_record'
   gem.add_development_dependency 'rake'
   gem.add_development_dependency 'rspec', '>= 2.12.0', '< 4.0'
-  gem.add_development_dependency 'sqlite3'
+  gem.add_development_dependency 'sqlite3', '~> 1.3.6'
   gem.add_development_dependency 'timecop'
 end
diff --git a/spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb b/spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb
index 562d7bfdb574d8ef12445f74078b5405f0d764de..9de0b2f0586d2ca889f9954ab50d01056d453a6f 100644
--- a/spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb
+++ b/spec/roqua/core_ext/enumerable/sort_by_alphanum_spec.rb
@@ -2,20 +2,17 @@ require 'roqua/core_ext/enumerable/sort_by_alphanum'
 
 describe Enumerable do
   describe '#sort_by_alphanum' do
+    let(:input) { ["004some11thing", "004some10thing", "3another"] }
     it 'sorts by chunks' do
-      ["004some11thing",
-       "004some10thing",
-       "3another"].sort_by_alphanum.should == ["3another", "004some10thing", "004some11thing"]
+      expect(input.sort_by_alphanum).to eq ["3another", "004some10thing", "004some11thing"]
     end
 
     it 'can take a block which can transform values before comparison' do
-      ["004some11thing",
-       "004some10thing",
-       "3another"].sort_by_alphanum(&:reverse).should == ["004some10thing", "004some11thing", "3another"]
+      expect(input.sort_by_alphanum(&:reverse)).to eq ["004some10thing", "004some11thing", "3another"]
     end
 
     it 'compares number chunks as integers' do
-      %w(004 3).sort_by_alphanum.should == %w(3 004)
+      expect(%w(004 3).sort_by_alphanum).to eq %w(3 004)
     end
   end
-end
\ No newline at end of file
+end
diff --git a/spec/roqua/core_ext/fabrication/singleton_spec.rb b/spec/roqua/core_ext/fabrication/singleton_spec.rb
index b812b909c67160f0093cb82841ab21cb5d3a71f1..4009677e81152ec82ecc408f637dda25531911e0 100644
--- a/spec/roqua/core_ext/fabrication/singleton_spec.rb
+++ b/spec/roqua/core_ext/fabrication/singleton_spec.rb
@@ -6,11 +6,13 @@ end
 
 describe Fabricate do
   it "returns singleton objects" do
-    Fabricate.singleton(:one).should == Fabricate.singleton(:one)
+    # Fabricate.singleton(:one).should == Fabricate.singleton(:one)
+    expect(Fabricate.singleton(:one)).to eq Fabricate.singleton(:one)
   end
 
   it 'maintains multiple singletons' do
-    Fabricate.singleton(:one).should_not == Fabricate.singleton(:two)
+    # Fabricate.singleton(:one).should_not == Fabricate.singleton(:two)
+    expect(Fabricate.singleton(:one)).not_to eq Fabricate.singleton(:two)
   end
 
   it 'clears singletons' do
@@ -19,4 +21,3 @@ describe Fabricate do
     expect(Fabricate.singleton(:one)).not_to eq(the_one)
   end
 end
-
diff --git a/spec/roqua/core_ext/fixnum/clamp_spec.rb b/spec/roqua/core_ext/fixnum/clamp_spec.rb
deleted file mode 100644
index 4889102b5a802d27a6b91fb86a26ced6b70a1812..0000000000000000000000000000000000000000
--- a/spec/roqua/core_ext/fixnum/clamp_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require 'roqua/core_ext/fixnum/clamp'
-
-describe Fixnum do
-  describe '#clamp' do
-    it "returns self if within bounds" do
-      5.clamp(1,10).should == 5
-    end
-
-    it "returns the lower bound if self < low" do
-      5.clamp(8,10).should == 8
-    end
-
-    it "returns the upper bound if self > high" do
-      5.clamp(1,3).should == 3
-    end
-
-    it "should raise an exception if the lower bound is greater than the upper bound" do
-      expect {
-        5.clamp(10,1)
-      }.to raise_error
-    end
-  end
-end
diff --git a/spec/roqua/probes/delayed_job_probe_spec.rb b/spec/roqua/probes/delayed_job_probe_spec.rb
index de10d9b7063a5730cdb108956576763925bcb477..39c1151bff41510989e82952d5986d2bf8f0f716 100644
--- a/spec/roqua/probes/delayed_job_probe_spec.rb
+++ b/spec/roqua/probes/delayed_job_probe_spec.rb
@@ -40,7 +40,7 @@ describe Roqua::Probes::DelayedJobProbe do
       expect { Roqua::Probes::DelayedJobProbe.enable }
         .to change { Appsignal::Minutely.probes.count }.by(1)
 
-      expect(Appsignal::Minutely.probes.map(&:class)).to include(Roqua::Probes::DelayedJobProbe)
+      expect(Appsignal::Minutely.probes[:"Roqua::Probes::DelayedJobProbe"]).to be
     end
 
     it 'will not add the same probe twice if called multiple times' do
diff --git a/spec/roqua/support/helpers_spec.rb b/spec/roqua/support/helpers_spec.rb
index 17a987e55c0449eb2dbcf151d6f21fe6184862b7..8a3e21882a3a80515fb97927e4d4f1bc789f47cb 100644
--- a/spec/roqua/support/helpers_spec.rb
+++ b/spec/roqua/support/helpers_spec.rb
@@ -23,7 +23,7 @@ describe 'Helper methods' do
       end
 
       it 'returns the value returned by the block' do
-        with_instrumentation('testevent') { 1 + 1 }.should == 2
+        expect(with_instrumentation('testevent') { 1 + 1 }).to eq 2
       end
     end
 
diff --git a/spec/roqua/support/logwrapper_spec.rb b/spec/roqua/support/logwrapper_spec.rb
index 727ee0acb6a48674ed212967c1666e96e665d681..61c19cf2af1d4fefdd916fae792a5283080ee54c 100644
--- a/spec/roqua/support/logwrapper_spec.rb
+++ b/spec/roqua/support/logwrapper_spec.rb
@@ -4,7 +4,7 @@ require 'stringio'
 
 module Roqua
   describe LogWrapper do
-    before { Roqua.stub(appname: 'roqua-support-testsuite') }
+    before { allow(Roqua).to receive(:appname).and_return('roqua-support-testsuite') }
 
     let(:logstream)  { StringIO.new }
     let(:logger)     { Logger.new(logstream) }
@@ -17,17 +17,17 @@ module Roqua
     describe '#add' do
       it 'writes event name to log' do
         logwrapper.add :info, "testevent"
-        log.should include("testevent {}\n")
+        expect(log).to include("testevent {}\n")
       end
 
       it 'writes given parameters as json hash' do
         logwrapper.add :info, "testevent", extra: 'params', go: 'here'
-        log.should include('testevent {"extra":"params","go":"here"}' + "\n")
+        expect(log).to include('testevent {"extra":"params","go":"here"}' + "\n")
       end
 
       it 'escapes newline characters in params' do
         logwrapper.add :info, "testevent", param: "this\nshould not have newlines"
-        log.should include('testevent {"param":"this\nshould not have newlines"')
+        expect(log).to include('testevent {"param":"this\nshould not have newlines"')
       end
     end
 
@@ -36,25 +36,25 @@ module Roqua
         logwrapper.lifecycle 'testevent', extra: 'params' do
           1 + 1
         end
-        log.should include('testevent:started {"extra":"params"}')
-        log.should match(/testevent:finished.*"extra":"params"/)
+        expect(log).to include('testevent:started {"extra":"params"}')
+        expect(log).to match(/testevent:finished.*"extra":"params"/)
       end
 
       it 'logs the duration of the block with the finished event' do
         logwrapper.lifecycle('testevent') { 1 + 1 }
-        log.should match(/testevent:finished.*"duration":/)
+        expect(log).to match(/testevent:finished.*"duration":/)
       end
 
       it 'returns the value returned by the block' do
-        logwrapper.lifecycle('testevent') { 1 + 1 }.should == 2
+        expect(logwrapper.lifecycle('testevent') { 1 + 1 }).to eq 2
       end
 
       it 'logs the start and failure of a block if it raises' do
         logwrapper.lifecycle 'testevent' do
           raise StandardError, "Foo"
         end rescue nil
-        log.should include('testevent:started')
-        log.should include('testevent:failed {"exception":"StandardError","message":"Foo"}')
+        expect(log).to include('testevent:started')
+        expect(log).to include('testevent:failed {"exception":"StandardError","message":"Foo"}')
       end
 
       it 'reraises the exception' do
diff --git a/spec/roqua/support/request_logger_spec.rb b/spec/roqua/support/request_logger_spec.rb
index abeba8b2a8bf017e9e6d7c9aca5d47278b27fa8d..ae78fc3da0a818b2c4e24f342d5c19e09687d8ce 100644
--- a/spec/roqua/support/request_logger_spec.rb
+++ b/spec/roqua/support/request_logger_spec.rb
@@ -8,7 +8,8 @@ describe Roqua::Support::RequestLogger do
   let(:logger)     { Logger.new(logstream) }
   let(:logwrapper) { Roqua::LogWrapper.new(logger) }
 
-  before { Roqua.stub(logger: logwrapper) }
+  # before { Roqua.stub(logger: logwrapper) }
+  before { allow(Roqua).to receive(:logger).and_return(logwrapper) }
 
   def log
     logstream.string
@@ -29,47 +30,47 @@ describe Roqua::Support::RequestLogger do
 
     it "logs the URL" do
       subscriber.process_action(event)
-      logstream.string.should include('/home')
+      expect(logstream.string).to include('/home')
     end
 
     it "does not log the query string" do
       subscriber.process_action(event)
-      logstream.string.should_not include('?foo=bar')
+      expect(logstream.string).to_not include('?foo=bar')
     end
 
     it "logs the HTTP method" do
       subscriber.process_action(event)
-      logstream.string.should include('"method":"GET"')
+      expect(logstream.string).to include('"method":"GET"')
     end
 
     it "logs the status code returned" do
       subscriber.process_action(event)
-      logstream.string.should include('"status":200')
+      expect(logstream.string).to include('"status":200')
     end
 
     it "logs the controller and action" do
       subscriber.process_action(event)
-      logstream.string.should include('"controller":"home","action":"index"')
+      expect(logstream.string).to include('"controller":"home","action":"index"')
     end
 
     it 'logs request parameters' do
       subscriber.process_action(event)
-      logstream.string.should include('"params":{"foo":"bar"}')
+      expect(logstream.string).to include('"params":{"foo":"bar"}')
     end
 
     it "logs how long the request took" do
       subscriber.process_action(event)
-      logstream.string.should =~ /"duration":1000.0/
+      expect(logstream.string).to match /"duration":1000.0/
     end
 
     it "logs the view rendering time" do
       subscriber.process_action(event)
-      logstream.string.should =~ /"view":0.01/
+      expect(logstream.string).to match /"view":0.01/
     end
 
     it "logs the database rendering time" do
       subscriber.process_action(event)
-      logstream.string.should =~ /"db":0.02/
+      expect(logstream.string).to match /"db":0.02/
     end
 
     it 'logs extra information added in the controller' do
@@ -82,12 +83,12 @@ describe Roqua::Support::RequestLogger do
       end
       controller.new.index
       subscriber.process_action(event)
-      logstream.string.should include('"current_user":"johndoe"')
+      expect(logstream.string).to include('"current_user":"johndoe"')
 
       # next request should not still maintain this data
       logstream.truncate 0
       subscriber.process_action(event)
-      logstream.string.should_not include('current_user')
+      expect(logstream.string).to_not include('current_user')
     end
   end
 
@@ -104,15 +105,15 @@ describe Roqua::Support::RequestLogger do
 
     it "logs the 500 status when an exception occurred" do
       subscriber.process_action(event)
-      logstream.string.should =~ /"status":500/
-      logstream.string.should =~ /"error":"AbstractController::ActionNotFound:Route not found"/
+      expect(logstream.string).to match /"status":500/
+      expect(logstream.string).to match /"error":"AbstractController::ActionNotFound:Route not found"/
     end
 
     it "should return an unknown status when no status or exception is found" do
       event.payload[:status] = nil
       event.payload[:exception] = nil
       subscriber.process_action(event)
-      logstream.string.should =~ /"status":0/
+      expect(logstream.string).to match /"status":0/
     end
   end
 
@@ -136,12 +137,12 @@ describe Roqua::Support::RequestLogger do
     it 'logs the redirect' do
       subscriber.redirect_to(redirect)
       subscriber.process_action(event)
-      log.should include('"location":"http://example.com"')
+      expect(log).to include('"location":"http://example.com"')
 
       # next request should no longer get location
       logstream.truncate 0
       subscriber.process_action(event)
-      log.should_not include('location')
+      expect(log).to_not include('location')
     end
   end
 end
diff --git a/spec/roqua/support_spec.rb b/spec/roqua/support_spec.rb
index 39cc8c37c4ae200293624277c219d5384f1dd9f6..275a9dd702c30c4f2c7c1e7419e691937c92d3c8 100644
--- a/spec/roqua/support_spec.rb
+++ b/spec/roqua/support_spec.rb
@@ -3,7 +3,7 @@ require 'roqua/support'
 describe Roqua do
   describe '#logger' do
     it 'has a default' do
-      Roqua.logger.should be_an_instance_of(Roqua::LogWrapper)
+      expect(Roqua.logger).to be_an_instance_of(Roqua::LogWrapper)
     end
   end
 
@@ -12,8 +12,8 @@ describe Roqua do
 
     it 'wraps a given logger' do
       Roqua.logger = logger
-      Roqua.logger.should be_an_instance_of(Roqua::LogWrapper)
-      Roqua.logger.logger.should == logger
+      expect(Roqua.logger).to be_an_instance_of(Roqua::LogWrapper)
+      expect(Roqua.logger.logger).to eq logger
     end
   end
 end