├── test
├── dummy
│ ├── log
│ │ └── .keep
│ ├── lib
│ │ └── assets
│ │ │ └── .keep
│ ├── .ruby-version
│ ├── public
│ │ ├── favicon.ico
│ │ ├── apple-touch-icon.png
│ │ ├── apple-touch-icon-precomposed.png
│ │ ├── 500.html
│ │ ├── 422.html
│ │ └── 404.html
│ ├── app
│ │ ├── assets
│ │ │ ├── images
│ │ │ │ └── .keep
│ │ │ ├── javascripts
│ │ │ │ ├── channels
│ │ │ │ │ └── .keep
│ │ │ │ ├── cable.js
│ │ │ │ └── application.js
│ │ │ ├── config
│ │ │ │ └── manifest.js
│ │ │ └── stylesheets
│ │ │ │ └── application.css
│ │ ├── models
│ │ │ ├── concerns
│ │ │ │ └── .keep
│ │ │ └── application_record.rb
│ │ ├── controllers
│ │ │ ├── concerns
│ │ │ │ └── .keep
│ │ │ └── application_controller.rb
│ │ ├── views
│ │ │ └── layouts
│ │ │ │ ├── mailer.text.erb
│ │ │ │ ├── mailer.html.erb
│ │ │ │ └── application.html.erb
│ │ ├── helpers
│ │ │ └── application_helper.rb
│ │ ├── jobs
│ │ │ └── application_job.rb
│ │ ├── channels
│ │ │ └── application_cable
│ │ │ │ ├── channel.rb
│ │ │ │ └── connection.rb
│ │ └── mailers
│ │ │ └── application_mailer.rb
│ ├── package.json
│ ├── bin
│ │ ├── rake
│ │ ├── bundle
│ │ ├── rails
│ │ ├── yarn
│ │ ├── update
│ │ └── setup
│ ├── config
│ │ ├── spring.rb
│ │ ├── routes.rb
│ │ ├── environment.rb
│ │ ├── initializers
│ │ │ ├── mime_types.rb
│ │ │ ├── filter_parameter_logging.rb
│ │ │ ├── application_controller_renderer.rb
│ │ │ ├── cookies_serializer.rb
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── wrap_parameters.rb
│ │ │ ├── arask.rb
│ │ │ ├── assets.rb
│ │ │ ├── inflections.rb
│ │ │ └── content_security_policy.rb
│ │ ├── cable.yml
│ │ ├── boot.rb
│ │ ├── application.rb
│ │ ├── database.yml
│ │ ├── locales
│ │ │ └── en.yml
│ │ ├── storage.yml
│ │ ├── puma.rb
│ │ └── environments
│ │ │ ├── test.rb
│ │ │ ├── development.rb
│ │ │ └── production.rb
│ ├── config.ru
│ ├── Rakefile
│ └── db
│ │ ├── migrate
│ │ └── 20180615090101_create_arask_jobs.rb
│ │ └── schema.rb
├── run_first_time_test.rb
├── activejob_test.rb
├── class_reference_test.rb
├── run_all_test.rb
├── exception_block_test.rb
├── cron_test.rb
├── test_helper.rb
└── saves_to_db_test.rb
├── .travis.yml
├── lib
├── arask
│ ├── version.rb
│ ├── railtie.rb
│ ├── run_jobs.rb
│ ├── initialize.rb
│ ├── arask_job.rb
│ └── setup.rb
├── generators
│ └── arask
│ │ └── install_generator.rb
└── arask.rb
├── bin
└── test
├── .gitignore
├── .github
└── workflows
│ ├── test.yml
│ └── build-release.yml
├── Rakefile
├── Gemfile
├── arask.gemspec
├── MIT-LICENSE
├── README.md
└── Gemfile.lock
/test/dummy/log/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.4.1
--------------------------------------------------------------------------------
/test/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 3.0
4 |
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/lib/arask/version.rb:
--------------------------------------------------------------------------------
1 | module Arask
2 | VERSION = '1.2.6'
3 | end
4 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dummy",
3 | "private": true,
4 | "dependencies": {}
5 | }
6 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | end
3 |
--------------------------------------------------------------------------------
/test/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/test/dummy/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/bin/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | $: << File.expand_path("../test", __dir__)
3 |
4 | require "bundler/setup"
5 | require "rails/plugin/test"
6 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/test/dummy/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/test/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/test/dummy/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../config/application', __dir__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/test/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
3 | end
4 |
--------------------------------------------------------------------------------
/test/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/lib/arask/railtie.rb:
--------------------------------------------------------------------------------
1 | module Arask
2 | class Railtie < ::Rails::Railtie
3 | # Executes when the rails server is running
4 | server do
5 | Arask.init_jobs
6 | end if Rails::VERSION::MAJOR>=6
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: dummy_production
11 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | log/*.log
3 | *.gem
4 | pkg/
5 | test/dummy/db/*.sqlite3
6 | test/dummy/db/*.sqlite3-journal
7 | test/dummy/log/*.log
8 | test/dummy/node_modules/
9 | test/dummy/yarn-error.log
10 | test/dummy/storage/
11 | test/dummy/tmp/
12 | coverage/*
13 |
--------------------------------------------------------------------------------
/test/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3 |
4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
6 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180615090101_create_arask_jobs.rb:
--------------------------------------------------------------------------------
1 | class CreateAraskJobs < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :arask_jobs do |t|
4 | t.string :job
5 | t.datetime :execute_at
6 | t.string :interval
7 | end
8 | add_index :arask_jobs, :execute_at
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dummy
5 | <%= csrf_meta_tags %>
6 | <%= csp_meta_tag %>
7 |
8 | <%= stylesheet_link_tag 'application', media: 'all' %>
9 | <%= javascript_include_tag 'application' %>
10 |
11 |
12 |
13 | <%= yield %>
14 |
15 |
16 |
--------------------------------------------------------------------------------
/lib/arask/run_jobs.rb:
--------------------------------------------------------------------------------
1 | module Arask
2 | class RunJobs < ActiveJob::Base
3 | queue_as :default
4 |
5 | def perform
6 | begin
7 | AraskJob.transaction do
8 | AraskJob.where('execute_at < ?', DateTime.now).lock.each do |job|
9 | job.run
10 | end
11 | end
12 | rescue
13 | end
14 | Arask.queue_self
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/run_first_time_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Arask::Test < ActiveSupport::TestCase
4 |
5 | test 'arask honours run_first_time' do
6 | # Stop time (Yes I am God)
7 | travel_to Date.today.noon
8 |
9 | Arask.setup(true) do |arask|
10 | arask.create script: 'random', cron: '0 0 1 1 1', run_first_time: true
11 | end
12 | assert(Arask::AraskJob.first.execute_at == Time.now)
13 |
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/cable.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3 | //
4 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v3
11 | - name: Set up Ruby
12 | uses: ruby/setup-ruby@v1
13 | with:
14 | ruby-version: "3.1"
15 | bundler-cache: true
16 | - name: Install dependencies
17 | run: bundle install
18 | - name: Run tests
19 | run: bundle exec rake
20 |
--------------------------------------------------------------------------------
/test/activejob_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ImportCurrenciesJob < ApplicationJob
4 | def perform(*args)
5 | return :i_ran
6 | end
7 | end
8 |
9 | class Arask::Test < ActiveSupport::TestCase
10 | test 'can execute ActiveJob' do
11 | Arask.setup(true) do |arask|
12 | arask.create job: 'ImportCurrenciesJob', cron: '* * * * *', run_first_time: true
13 | end
14 | assert(Arask::AraskJob.first.run == :i_ran)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/test/class_reference_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ClassReferenceTest < ApplicationJob
4 | def perform(*args)
5 | return :i_ran2
6 | end
7 | end
8 |
9 | class Arask::Test < ActiveSupport::TestCase
10 | test 'can reference class instead of string' do
11 | Arask.setup(true) do |arask|
12 | arask.create job: ClassReferenceTest, cron: '* * * * *', run_first_time: true
13 | end
14 | assert(Arask::AraskJob.first.run == :i_ran2)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/generators/arask/install_generator.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators'
2 | require "rails/generators/active_record"
3 |
4 | class Arask::InstallGenerator < Rails::Generators::Base
5 | def initialize(*args, &block)
6 | super
7 |
8 | Arask::InstallGenerator.source_root File.expand_path('../../arask', __FILE__)
9 | copy_file '../../arask/initialize.rb', 'config/initializers/arask.rb'
10 |
11 | generate 'migration', 'create_arask_jobs job:string execute_at:datetime:index interval:string'
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/arask.rb:
--------------------------------------------------------------------------------
1 | Arask.setup do |arask|
2 | # Examples
3 | #arask.create script: 'puts "IM ALIVE!"', interval: :daily, run_first_time: true
4 | #arask.create script: 'Attachment.process_new', interval: 5.hours if Rails.env.production?
5 | #arask.create task: 'send:logs', cron: '0 2 * * *' # At 02:00 every day
6 | #arask.create task: 'update:cache', cron: '*/5 * * * *' # Every 5 minutes
7 | # Run rake task:
8 | #arask.create task: 'my:awesome_task', interval: :hourly
9 | # On exceptions, send email
10 | #arask.on_exception email: 'errors@example.com'
11 | end
12 |
--------------------------------------------------------------------------------
/.github/workflows/build-release.yml:
--------------------------------------------------------------------------------
1 | name: Build release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v*.*.*"
7 |
8 | jobs:
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set up Ruby 3.1
16 | uses: ruby/setup-ruby@v1
17 | with:
18 | ruby-version: 3.1
19 | bundler-cache: true
20 | - run: bundle install
21 |
22 | - name: Build gem
23 | run: |
24 | gem build arask
25 | - name: Release
26 | uses: softprops/action-gh-release@v1
27 | with:
28 | files: arask-*.gem
29 |
--------------------------------------------------------------------------------
/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails/all'
4 |
5 | Bundler.require(*Rails.groups)
6 | require "arask"
7 |
8 | module Dummy
9 | class Application < Rails::Application
10 | # Initialize configuration defaults for originally generated Rails version.
11 | config.load_defaults 5.2
12 |
13 | # Settings in config/environments/* take precedence over those specified here.
14 | # Application configuration can go into files in config/initializers
15 | # -- all .rb files in that directory are automatically loaded after loading
16 | # the framework and any gems in your application.
17 | end
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'bundler/setup'
3 | rescue LoadError
4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5 | end
6 |
7 | require 'rdoc/task'
8 |
9 | RDoc::Task.new(:rdoc) do |rdoc|
10 | rdoc.rdoc_dir = 'rdoc'
11 | rdoc.title = 'Arask'
12 | rdoc.options << '--line-numbers'
13 | rdoc.rdoc_files.include('README.md')
14 | rdoc.rdoc_files.include('lib/**/*.rb')
15 | end
16 |
17 | require 'bundler/gem_tasks'
18 |
19 | require 'rake/testtask'
20 |
21 | Rake::TestTask.new(:test) do |t|
22 | t.libs << 'test'
23 | t.pattern = 'test/**/*_test.rb'
24 | t.verbose = false
25 | t.warning = false
26 | end
27 |
28 | task default: :test
29 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | # Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | # Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in the app/assets
13 | # folder are already added.
14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 |
--------------------------------------------------------------------------------
/test/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | # Declare your gem's dependencies in arask.gemspec.
5 | # Bundler will treat runtime dependencies like base dependencies, and
6 | # development dependencies will be added by default to the :development group.
7 | gemspec
8 |
9 | group :test do
10 | gem 'coveralls', :require => false
11 | end
12 |
13 | # Declare any dependencies that are still in development here instead of in
14 | # your gemspec. These might include edge Rails or gems from your path or
15 | # Git. Remember to move these dependencies to your gemspec before releasing
16 | # your gem to rubygems.org.
17 |
18 | # To use a debugger
19 | # gem 'byebug', group: [:development, :test]
20 |
--------------------------------------------------------------------------------
/test/run_all_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Arask::Test < ActiveSupport::TestCase
4 | test 'actually runs all jobs' do
5 | # Stop time (Yes I am God)
6 | travel_to Time.utc(2000, 4, 5, 10, 0, 5)
7 |
8 | Arask.setup(true) do |arask|
9 | arask.create script: '1+1', cron: '* * * * *'
10 | arask.create script: '1+2', cron: '* * * * *'
11 | end
12 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 10, 1, 0))
13 | # Don't traverse time. Nothing should happen
14 | Arask::RunJobs.perform_now
15 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 10, 1, 0))
16 |
17 | travel 1.minute
18 | Arask::RunJobs.perform_now
19 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 10, 2, 0))
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file. JavaScript code in this file should be added after the last require_* statement.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require rails-ujs
14 | //= require activestorage
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/arask.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("lib", __dir__)
2 |
3 | # Maintain your gem's version:
4 | require "arask/version"
5 |
6 | # Describe your gem and declare its dependencies:
7 | Gem::Specification.new do |s|
8 | s.name = "arask"
9 | s.version = Arask::VERSION
10 | s.authors = ["Esben Damgaard"]
11 | s.email = ["ebbe@hvemder.dk"]
12 | s.homepage = "http://github.com/Ebbe/arask"
13 | s.summary = "Automatic RAils taSKs (with minimal setup)"
14 | s.description = "With minimal setup, be able to regularly run tasks in Rails. Either user cron syntax or simply define an interval."
15 | s.license = "MIT"
16 |
17 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
18 |
19 | s.add_dependency "rails", ">= 5.0"
20 | s.add_dependency "fugit", "~> 1.1"
21 |
22 | s.add_development_dependency "sqlite3"
23 | end
24 |
--------------------------------------------------------------------------------
/test/exception_block_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Arask::Test < ActiveSupport::TestCase
4 | test 'can execute an exception block' do
5 | old_stdout = $stdout
6 | $stdout = StringIO.new
7 |
8 | exception_text = nil
9 | exception_job_text = nil
10 | Arask.setup(true) do |arask|
11 | arask.create script: 'puts "no error"', cron: '* * * * *', run_first_time: true
12 | arask.create script: 'raise "Message!"', cron: '* * * * *', run_first_time: true
13 | arask.create script: 'puts "no error"', cron: '* * * * *', run_first_time: true
14 |
15 | arask.on_exception do |exception, job|
16 | exception_text = exception.to_s
17 | exception_job_text = job.job
18 | end
19 | end
20 | Arask::RunJobs.perform_now
21 | assert(exception_text == "Message!")
22 | assert(exception_job_text == 'raise "Message!"')
23 |
24 | $stdout = old_stdout
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/dummy/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a way to update your development environment automatically.
14 | # Add necessary update steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | puts "\n== Updating database =="
24 | system! 'bin/rails db:migrate'
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! 'bin/rails log:clear tmp:clear'
28 |
29 | puts "\n== Restarting application server =="
30 | system! 'bin/rails restart'
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/test/cron_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Arask::Test < ActiveSupport::TestCase
4 |
5 | test 'can read normal cron syntax' do
6 | # Stop time (Yes I am God)
7 | travel_to Time.utc(2000, 4, 5, 10, 0, 5)
8 |
9 | Arask.setup(true) do |arask|
10 | arask.create script: 'random"', cron: '* * * * *'
11 | end
12 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 10, 1, 0))
13 |
14 | Arask.setup(true) do |arask|
15 | arask.create script: 'random"', cron: '0 * * * *'
16 | end
17 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 11, 0, 0))
18 |
19 | Arask.setup(true) do |arask|
20 | arask.create script: 'random"', cron: '0 2 * * *'
21 | end
22 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 6, 2, 0, 0))
23 |
24 | Arask.setup(true) do |arask|
25 | arask.create script: 'random"', cron: '*/5 * * * *'
26 | end
27 | assert(Arask::AraskJob.first.execute_at == Time.utc(2000, 4, 5, 10, 5, 0))
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 2018_06_15_090101) do
14 |
15 | create_table "arask_jobs", force: :cascade do |t|
16 | t.string "job"
17 | t.datetime "execute_at"
18 | t.string "interval"
19 | t.index ["execute_at"], name: "index_arask_jobs_on_execute_at"
20 | end
21 |
22 | end
23 |
--------------------------------------------------------------------------------
/test/dummy/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a starting point to setup your application.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | # puts "\n== Copying sample files =="
24 | # unless File.exist?('config/database.yml')
25 | # cp 'config/database.yml.sample', 'config/database.yml'
26 | # end
27 |
28 | puts "\n== Preparing database =="
29 | system! 'bin/rails db:setup'
30 |
31 | puts "\n== Removing old logs and tempfiles =="
32 | system! 'bin/rails log:clear tmp:clear'
33 |
34 | puts "\n== Restarting application server =="
35 | system! 'bin/rails restart'
36 | end
37 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Esben Damgaard
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # Configure Rails Environment
2 | ENV["RAILS_ENV"] = "test"
3 |
4 | # require 'coveralls'
5 | # Coveralls.wear!
6 |
7 | require_relative "../test/dummy/config/environment"
8 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
9 | require "rails/test_help"
10 |
11 | # Filter out Minitest backtrace while allowing backtrace from other libraries
12 | # to be shown.
13 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new
14 |
15 | require "rails/test_unit/reporter"
16 | Rails::TestUnitReporter.executable = 'bin/test'
17 |
18 | # Load fixtures from the engine
19 | if ActiveSupport::TestCase.respond_to?(:fixture_path=)
20 | ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__)
21 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
22 | ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
23 | ActiveSupport::TestCase.fixtures :all
24 | end
25 |
26 |
27 | # Setup db
28 | ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
29 | load File.dirname(__FILE__) + '/dummy/db/schema.rb'
30 |
--------------------------------------------------------------------------------
/lib/arask/initialize.rb:
--------------------------------------------------------------------------------
1 | Arask.setup do |arask|
2 | ## Examples
3 |
4 | # Rake tasks with cron syntax
5 | #arask.create task: 'send:logs', cron: '0 2 * * *' # At 02:00 every day
6 | #arask.create task: 'update:cache', cron: '*/5 * * * *' # Every 5 minutes
7 |
8 | # Scripts with interval (when time of day or month etc doesn't matter)
9 | #arask.create script: 'puts "IM ALIVE!"', interval: :daily
10 | #arask.create task: 'my:awesome_task', interval: :hourly
11 | #arask.create task: 'my:awesome_task', interval: 3.minutes
12 |
13 | # Run an ActiveJob.
14 | #arask.create job: 'ImportCurrenciesJob', interval: 1.month
15 |
16 | # Only run on production
17 | #arask.create script: 'Attachment.process_new', interval: 5.hours if Rails.env.production?
18 |
19 | # Run first time. If the job didn't exist already when starting rails, run it:
20 | #arask.create script: 'Attachment.process_new', interval: 5.hours, run_first_time: true
21 |
22 | # On exceptions, send email with details
23 | #arask.on_exception email: 'errors@example.com'
24 |
25 | # Run code on exceptions
26 | #arask.on_exception do |exception, arask_job|
27 | # MyExceptionHandler.new(exception)
28 | #end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 |
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 |
19 | # If you are using UJS then enable automatic nonce generation
20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21 |
22 | # Report CSP violations to a specified URI
23 | # For further information see the following documentation:
24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
25 | # Rails.application.config.content_security_policy_report_only = true
26 |
--------------------------------------------------------------------------------
/test/dummy/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/test/saves_to_db_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Arask::Test < ActiveSupport::TestCase
4 | include ActiveJob::TestHelper
5 |
6 | test "truth" do
7 | assert_kind_of Module, Arask
8 | end
9 |
10 | test 'sets correct execute_at and queues the next job' do
11 | assert(Arask.respond_to? :setup)
12 |
13 | assert_no_enqueued_jobs
14 |
15 | # Stop time (Yes I am God)
16 | travel_to Time.current
17 |
18 |
19 | assert_enqueued_with at: 2.minutes.from_now do
20 | Arask.setup(true) do |arask|
21 | arask.create script: 'random', interval: 2.minutes
22 | end
23 | assert(Arask::AraskJob.first.execute_at == 2.minutes.from_now)
24 | assert_enqueued_jobs 1
25 | end
26 |
27 | Arask.setup(true) do |arask|
28 | arask.create script: 'random2"', interval: 10.hours
29 | end
30 | assert(Arask::AraskJob.first.execute_at == 10.hours.from_now)
31 |
32 | Arask.setup(true) do |arask|
33 | arask.create script: 'random3', interval: 5.days
34 | end
35 | assert(Arask::AraskJob.first.execute_at == 5.days.from_now)
36 | end
37 |
38 | test 'maximum wait time is 1 day' do
39 | travel_to Time.current
40 | assert_enqueued_with at: 1.day.from_now do
41 | Arask.setup(true) do |arask|
42 | arask.create script: 'random"', interval: 25.hours
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/arask/arask_job.rb:
--------------------------------------------------------------------------------
1 | module Arask
2 | require 'rake'
3 |
4 | class AraskJob < ActiveRecord::Base
5 | after_create :calculate_new_execute_at
6 |
7 | def run
8 | calculate_new_execute_at
9 | begin
10 | if self.job.start_with?('Rake::Task')
11 | Rake.load_rakefile Rails.root.join('Rakefile') unless Rake::Task.task_defined?(self.job[12..-3])
12 | eval(self.job + '.invoke')
13 | eval(self.job + '.reenable')
14 | else
15 | eval(self.job)
16 | end
17 | rescue Exception => e
18 | puts 'Arask: Job failed'
19 | p self
20 | puts e.message
21 |
22 | unless Arask.exception_block.nil?
23 | Arask.exception_block.call(e, self)
24 | end
25 | unless Arask.exception_email.nil?
26 | ActionMailer::Base.mail(
27 | from: Arask.exception_email_from,
28 | to: Arask.exception_email,
29 | subject: "Arask failed",
30 | body: "Job: #{self.inspect}\n\nException:\n#{e.message}"
31 | ).deliver
32 | end
33 | end
34 | end
35 |
36 | private
37 | def calculate_new_execute_at
38 | if self.interval.start_with?('cron: ')
39 | cron = Fugit::Cron.parse(self.interval.split(' ', 2)[1])
40 | self.update_attribute(:execute_at, cron.next_time.to_t)
41 | else
42 | self.update_attribute(:execute_at, self.interval.to_i.seconds.from_now)
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/test/dummy/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | threads threads_count, threads_count
9 |
10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11 | #
12 | port ENV.fetch("PORT") { 3000 }
13 |
14 | # Specifies the `environment` that Puma will run in.
15 | #
16 | environment ENV.fetch("RAILS_ENV") { "development" }
17 |
18 | # Specifies the number of `workers` to boot in clustered mode.
19 | # Workers are forked webserver processes. If using threads and workers together
20 | # the concurrency of the application would be max `threads` * `workers`.
21 | # Workers do not work on JRuby or Windows (both of which do not support
22 | # processes).
23 | #
24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25 |
26 | # Use the `preload_app!` method when specifying a `workers` number.
27 | # This directive tells Puma to first boot the application and load code
28 | # before forking the application. This takes advantage of Copy On Write
29 | # process behavior so workers use less memory.
30 | #
31 | # preload_app!
32 |
33 | # Allow puma to be restarted by `rails restart` command.
34 | plugin :tmp_restart
35 |
--------------------------------------------------------------------------------
/lib/arask.rb:
--------------------------------------------------------------------------------
1 | require "arask/railtie"
2 | require "arask/arask_job"
3 | require "arask/run_jobs"
4 | require "arask/setup"
5 | require 'fugit' # To parse cron
6 |
7 | module Arask
8 | class << self; attr_accessor :jobs_touched, :exception_email, :exception_email_from, :exception_block, :jobs_block; end
9 |
10 | def self.setup(force_run = false, &block)
11 | Arask.jobs_block = block
12 | if Rails::VERSION::MAJOR>=6
13 | # Make sure we only run setup now if we are testing.
14 | # Else we would run them at every cli execution.
15 | # railtie.rb inits the jobs when the server is ready
16 | Arask.init_jobs if force_run
17 | else # Rails is less than 6
18 |
19 | # Make sure we only run setup if Rails is actually run as a server or testing.
20 | return unless defined?(Rails::Server) or force_run
21 | # If we don't wait and rails is setup to use another language, ActiveJob
22 | # saves what is now (usually :en) and reloads that when trying to run the
23 | # job. Renderering an I18n error of unsupported language.
24 | ActiveSupport.on_load :after_initialize, yield: true do
25 | Arask.init_jobs
26 | end
27 | end
28 | end
29 |
30 | def self.init_jobs
31 | Arask.jobs_touched = []
32 | Arask.jobs_block.call(Setup)
33 | Arask.jobs_block = nil
34 | begin
35 | AraskJob.all.where.not(id: Arask.jobs_touched).delete_all
36 | Arask.jobs_touched = nil
37 | Arask.queue_self
38 | rescue
39 | end
40 | end
41 |
42 | def self.queue_self
43 | begin
44 | next_job_run = AraskJob.order(execute_at: :asc).first.try(:execute_at)
45 | # At least check database for jobs every day
46 | next_job_run = 1.day.from_now if next_job_run.nil? or (next_job_run - DateTime.now)/60/60 > 24
47 | RunJobs.set(wait_until: next_job_run).perform_later
48 | rescue
49 | end
50 | end
51 |
52 | end
53 |
--------------------------------------------------------------------------------
/test/dummy/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/test/dummy/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 |
31 | # Store uploaded files on the local file system in a temporary directory
32 | config.active_storage.service = :test
33 |
34 | config.action_mailer.perform_caching = false
35 |
36 | # Tell Action Mailer not to deliver emails to the real world.
37 | # The :test delivery method accumulates sent emails in the
38 | # ActionMailer::Base.deliveries array.
39 | config.action_mailer.delivery_method = :test
40 |
41 | # Print deprecation notices to the stderr.
42 | config.active_support.deprecation = :stderr
43 |
44 | # Raises error for missing translations
45 | # config.action_view.raise_on_missing_translations = true
46 | end
47 |
--------------------------------------------------------------------------------
/lib/arask/setup.rb:
--------------------------------------------------------------------------------
1 | module Arask
2 | class Setup
3 | def self.on_exception(email: nil, from: 'robot@server', &block)
4 | Arask.exception_email = email unless email.nil?
5 | Arask.exception_email_from = from unless from.nil?
6 | puts "Arask could not parse parameter for on_exception!" unless email.nil? or email.class == String
7 | if block_given?
8 | Arask.exception_block = block
9 | end
10 | end
11 |
12 | def self.create(script: nil, task: nil, job: nil, interval: nil, cron: nil, run_first_time: false)
13 | interval = parse_interval_or_cron(interval, cron)
14 | if interval.nil?
15 | puts 'Arask: You did not specify neither cron: nor interval:! When should the task run?'
16 | return
17 | end
18 | unless task.nil?
19 | script = "Rake::Task['#{task}']"
20 | end
21 | unless job.nil?
22 | script = "#{job}.perform_now"
23 | end
24 | if script.nil?
25 | puts 'Arask: You did not specify a script or task to run!'
26 | return
27 | end
28 | begin
29 | job = AraskJob.where(job: script, interval: interval).first
30 | if job
31 | Arask.jobs_touched << job.id
32 | else
33 | job = AraskJob.create(job: script, interval: interval)
34 | Arask.jobs_touched << job.id
35 | if run_first_time===true
36 | job.update_attribute(:execute_at, Time.now)
37 | end
38 | end
39 | rescue ActiveRecord::StatementInvalid => e
40 | puts 'Could not create arask job! Looks like the database is not migrated? Remember to run `rails generate arask:install` and `rails db:migrate`'
41 | end
42 | end
43 |
44 | private
45 | def self.parse_interval_or_cron(interval, cron)
46 | unless interval.nil?
47 | case interval
48 | when :hourly
49 | interval = 1.hour
50 | when :daily
51 | interval = 1.day
52 | when :monthly
53 | interval = 1.month
54 | end
55 | interval = interval.to_s.to_i
56 | end
57 | unless cron.nil?
58 | interval = 'cron: ' + cron
59 | end
60 | return interval
61 | end
62 |
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | # Run rails dev:cache to toggle caching.
17 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
18 | config.action_controller.perform_caching = true
19 |
20 | config.cache_store = :memory_store
21 | config.public_file_server.headers = {
22 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
23 | }
24 | else
25 | config.action_controller.perform_caching = false
26 |
27 | config.cache_store = :null_store
28 | end
29 |
30 | # Store uploaded files on the local file system (see config/storage.yml for options)
31 | config.active_storage.service = :local
32 |
33 | # Don't care if the mailer can't send.
34 | config.action_mailer.raise_delivery_errors = false
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Print deprecation notices to the Rails logger.
39 | config.active_support.deprecation = :log
40 |
41 | # Raise an error on page load if there are pending migrations.
42 | config.active_record.migration_error = :page_load
43 |
44 | # Highlight code that triggered database queries in logs.
45 | config.active_record.verbose_query_logs = true
46 |
47 | # Debug mode disables concatenation and preprocessing of assets.
48 | # This option may cause significant delays in view rendering with a large
49 | # number of complex assets.
50 | config.assets.debug = true
51 |
52 | # Suppress logger output for asset requests.
53 | config.assets.quiet = true
54 |
55 | # Raises error for missing translations
56 | # config.action_view.raise_on_missing_translations = true
57 |
58 | # Use an evented file watcher to asynchronously detect changes in source code,
59 | # routes, locales, etc. This feature depends on the listen gem.
60 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker
61 | end
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arask
2 |
3 | [](https://badge.fury.io/rb/arask)
4 | [](https://coveralls.io/github/Ebbe/arask?branch=master)
5 |
6 | Automatic RAils taSKs (with minimal setup).
7 |
8 | No need to setup anything outside of Rails. If Rails is running, so is Arask. If Rails has been stopped, the next time rails starts, Arask will go through overdue jobs and perform them.
9 |
10 | Use cron syntax or simply define the interval.
11 |
12 | ## Installation
13 |
14 | Add this line to your application's Gemfile:
15 |
16 | ```ruby
17 | gem 'arask'
18 | ```
19 |
20 | Execute:
21 |
22 | ```bash
23 | $ bundle install
24 | $ rails generate arask:install
25 | $ rails db:migrate
26 | ```
27 |
28 | Setup your tasks in config/initializers/arask.rb. Initially it looks [like this](lib/arask/initialize.rb).
29 |
30 | ## Usage
31 |
32 | After installation, you can edit config/initializers/arask.rb with your tasks.
33 |
34 | ### Examples of jobs in the initializer
35 |
36 | ```ruby
37 | # Rake tasks with cron syntax
38 | arask.create task: 'send:logs', cron: '0 2 * * *' # At 02:00 every day
39 | arask.create task: 'update:cache', cron: '*/5 * * * *' # Every 5 minutes
40 |
41 | # Scripts with interval (when time of day or month etc doesn't matter)
42 | arask.create script: 'puts "IM ALIVE!"', interval: :daily
43 | arask.create task: 'my:awesome_task', interval: :hourly
44 | arask.create task: 'my:awesome_task', interval: 3.minutes
45 |
46 | # Run an ActiveJob.
47 | arask.create job: 'ImportCurrenciesJob', interval: 1.month
48 |
49 | # Only run on production
50 | arask.create script: 'Attachment.process_new', interval: 5.hours if Rails.env.production?
51 |
52 | # Run first time. If the job didn't exist already when starting rails, run it:
53 | arask.create script: 'Attachment.process_new', interval: 5.hours, run_first_time: true
54 |
55 | # On exceptions, send email with details
56 | arask.on_exception email: 'errors@example.com'
57 |
58 | # Run code on exceptions
59 | arask.on_exception do |exception, arask_job|
60 | MyExceptionHandler.new(exception)
61 | end
62 | ```
63 |
64 | ### About cron
65 |
66 | Arask uses [fugit](https://github.com/floraison/fugit) to parse cron and get next execution time. It follows normal cron syntax. You can test your cron at https://crontab.guru/.
67 |
68 | Not supported is `@reboot`.
69 |
70 | ### About interval
71 |
72 | The interval starts when the task has started running. If a task with the interval `:hourly` is run at 08:37PM, then it will run the next time at 09:37PM.
73 |
74 | ## Todos
75 |
76 | - Have a "try again" feature. For instance `arask.create script: 'raise "I failed"', interval: :daily, fail_retry: 5.minutes, retry_at_most: 2`
77 | - Be able to specify line and number that failed for an exception:
78 |
79 | ```ruby
80 | file,line,_ = caller.first.split(':')
81 | fileline = File.readlines(file)[line.to_i - 1].strip
82 | ```
83 |
84 | ## Special environments
85 |
86 | ### Heroku
87 |
88 | Nothing special to setup. But if you use a hobby dyno and it falls to sleep, so will Arask. As soon as the dyno wakes up, Arask will run any pending jobs.
89 |
90 | ### Docker
91 |
92 | Nothing special to setup.
93 |
94 | ## Caveats
95 |
96 | If you reload a database dump, your jobs could be run again.
97 |
98 | ## Contributing
99 |
100 | Please use https://github.com/Ebbe/arask
101 |
102 | ## Running tests
103 |
104 | ```bash
105 | $ bundle install
106 | $ bundle exec rake test
107 | ```
108 |
109 | ## License
110 |
111 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
112 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
19 | # config.require_master_key = true
20 |
21 | # Disable serving static files from the `/public` folder by default since
22 | # Apache or NGINX already handles this.
23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
33 |
34 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
35 | # config.action_controller.asset_host = 'http://assets.example.com'
36 |
37 | # Specifies the header that your server uses for sending files.
38 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
39 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
40 |
41 | # Store uploaded files on the local file system (see config/storage.yml for options)
42 | config.active_storage.service = :local
43 |
44 | # Mount Action Cable outside main process or domain
45 | # config.action_cable.mount_path = nil
46 | # config.action_cable.url = 'wss://example.com/cable'
47 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
48 |
49 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
50 | # config.force_ssl = true
51 |
52 | # Use the lowest log level to ensure availability of diagnostic information
53 | # when problems arise.
54 | config.log_level = :debug
55 |
56 | # Prepend all log lines with the following tags.
57 | config.log_tags = [ :request_id ]
58 |
59 | # Use a different cache store in production.
60 | # config.cache_store = :mem_cache_store
61 |
62 | # Use a real queuing backend for Active Job (and separate queues per environment)
63 | # config.active_job.queue_adapter = :resque
64 | # config.active_job.queue_name_prefix = "dummy_#{Rails.env}"
65 |
66 | config.action_mailer.perform_caching = false
67 |
68 | # Ignore bad email addresses and do not raise email delivery errors.
69 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
70 | # config.action_mailer.raise_delivery_errors = false
71 |
72 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
73 | # the I18n.default_locale when a translation cannot be found).
74 | config.i18n.fallbacks = true
75 |
76 | # Send deprecation notices to registered listeners.
77 | config.active_support.deprecation = :notify
78 |
79 | # Use default logging formatter so that PID and timestamp are not suppressed.
80 | config.log_formatter = ::Logger::Formatter.new
81 |
82 | # Use a different logger for distributed setups.
83 | # require 'syslog/logger'
84 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
85 |
86 | if ENV["RAILS_LOG_TO_STDOUT"].present?
87 | logger = ActiveSupport::Logger.new(STDOUT)
88 | logger.formatter = config.log_formatter
89 | config.logger = ActiveSupport::TaggedLogging.new(logger)
90 | end
91 |
92 | # Do not dump schema after migrations.
93 | config.active_record.dump_schema_after_migration = false
94 | end
95 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | arask (1.2.6)
5 | fugit (~> 1.1)
6 | rails (>= 5.0)
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | actioncable (7.1.5.2)
12 | actionpack (= 7.1.5.2)
13 | activesupport (= 7.1.5.2)
14 | nio4r (~> 2.0)
15 | websocket-driver (>= 0.6.1)
16 | zeitwerk (~> 2.6)
17 | actionmailbox (7.1.5.2)
18 | actionpack (= 7.1.5.2)
19 | activejob (= 7.1.5.2)
20 | activerecord (= 7.1.5.2)
21 | activestorage (= 7.1.5.2)
22 | activesupport (= 7.1.5.2)
23 | mail (>= 2.7.1)
24 | net-imap
25 | net-pop
26 | net-smtp
27 | actionmailer (7.1.5.2)
28 | actionpack (= 7.1.5.2)
29 | actionview (= 7.1.5.2)
30 | activejob (= 7.1.5.2)
31 | activesupport (= 7.1.5.2)
32 | mail (~> 2.5, >= 2.5.4)
33 | net-imap
34 | net-pop
35 | net-smtp
36 | rails-dom-testing (~> 2.2)
37 | actionpack (7.1.5.2)
38 | actionview (= 7.1.5.2)
39 | activesupport (= 7.1.5.2)
40 | nokogiri (>= 1.8.5)
41 | racc
42 | rack (>= 2.2.4)
43 | rack-session (>= 1.0.1)
44 | rack-test (>= 0.6.3)
45 | rails-dom-testing (~> 2.2)
46 | rails-html-sanitizer (~> 1.6)
47 | actiontext (7.1.5.2)
48 | actionpack (= 7.1.5.2)
49 | activerecord (= 7.1.5.2)
50 | activestorage (= 7.1.5.2)
51 | activesupport (= 7.1.5.2)
52 | globalid (>= 0.6.0)
53 | nokogiri (>= 1.8.5)
54 | actionview (7.1.5.2)
55 | activesupport (= 7.1.5.2)
56 | builder (~> 3.1)
57 | erubi (~> 1.11)
58 | rails-dom-testing (~> 2.2)
59 | rails-html-sanitizer (~> 1.6)
60 | activejob (7.1.5.2)
61 | activesupport (= 7.1.5.2)
62 | globalid (>= 0.3.6)
63 | activemodel (7.1.5.2)
64 | activesupport (= 7.1.5.2)
65 | activerecord (7.1.5.2)
66 | activemodel (= 7.1.5.2)
67 | activesupport (= 7.1.5.2)
68 | timeout (>= 0.4.0)
69 | activestorage (7.1.5.2)
70 | actionpack (= 7.1.5.2)
71 | activejob (= 7.1.5.2)
72 | activerecord (= 7.1.5.2)
73 | activesupport (= 7.1.5.2)
74 | marcel (~> 1.0)
75 | activesupport (7.1.5.2)
76 | base64
77 | benchmark (>= 0.3)
78 | bigdecimal
79 | concurrent-ruby (~> 1.0, >= 1.0.2)
80 | connection_pool (>= 2.2.5)
81 | drb
82 | i18n (>= 1.6, < 2)
83 | logger (>= 1.4.2)
84 | minitest (>= 5.1)
85 | mutex_m
86 | securerandom (>= 0.3)
87 | tzinfo (~> 2.0)
88 | base64 (0.3.0)
89 | benchmark (0.4.1)
90 | bigdecimal (3.2.2)
91 | builder (3.3.0)
92 | concurrent-ruby (1.3.5)
93 | connection_pool (2.5.3)
94 | coveralls (0.8.23)
95 | json (>= 1.8, < 3)
96 | simplecov (~> 0.16.1)
97 | term-ansicolor (~> 1.3)
98 | thor (>= 0.19.4, < 2.0)
99 | tins (~> 1.6)
100 | crass (1.0.6)
101 | date (3.4.1)
102 | docile (1.3.5)
103 | drb (2.2.3)
104 | erubi (1.13.0)
105 | et-orbi (1.2.11)
106 | tzinfo
107 | fugit (1.11.1)
108 | et-orbi (~> 1, >= 1.2.11)
109 | raabro (~> 1.4)
110 | globalid (1.2.1)
111 | activesupport (>= 6.1)
112 | i18n (1.14.7)
113 | concurrent-ruby (~> 1.0)
114 | io-console (0.7.2)
115 | irb (1.11.2)
116 | rdoc
117 | reline (>= 0.4.2)
118 | json (2.5.1)
119 | logger (1.7.0)
120 | loofah (2.23.1)
121 | crass (~> 1.0.2)
122 | nokogiri (>= 1.12.0)
123 | mail (2.8.1)
124 | mini_mime (>= 0.1.1)
125 | net-imap
126 | net-pop
127 | net-smtp
128 | marcel (1.0.4)
129 | mini_mime (1.1.2)
130 | mini_portile2 (2.8.9)
131 | minitest (5.25.5)
132 | mutex_m (0.3.0)
133 | net-imap (0.3.9)
134 | date
135 | net-protocol
136 | net-pop (0.1.2)
137 | net-protocol
138 | net-protocol (0.2.2)
139 | timeout
140 | net-smtp (0.3.3)
141 | net-protocol
142 | nio4r (2.5.8)
143 | nokogiri (1.18.9)
144 | mini_portile2 (~> 2.8.2)
145 | racc (~> 1.4)
146 | psych (5.1.2)
147 | stringio
148 | raabro (1.4.0)
149 | racc (1.8.1)
150 | rack (3.1.18)
151 | rack-session (2.1.1)
152 | base64 (>= 0.1.0)
153 | rack (>= 3.0.0)
154 | rack-test (2.1.0)
155 | rack (>= 1.3)
156 | rackup (2.1.0)
157 | rack (>= 3)
158 | webrick (~> 1.8)
159 | rails (7.1.5.2)
160 | actioncable (= 7.1.5.2)
161 | actionmailbox (= 7.1.5.2)
162 | actionmailer (= 7.1.5.2)
163 | actionpack (= 7.1.5.2)
164 | actiontext (= 7.1.5.2)
165 | actionview (= 7.1.5.2)
166 | activejob (= 7.1.5.2)
167 | activemodel (= 7.1.5.2)
168 | activerecord (= 7.1.5.2)
169 | activestorage (= 7.1.5.2)
170 | activesupport (= 7.1.5.2)
171 | bundler (>= 1.15.0)
172 | railties (= 7.1.5.2)
173 | rails-dom-testing (2.2.0)
174 | activesupport (>= 5.0.0)
175 | minitest
176 | nokogiri (>= 1.6)
177 | rails-html-sanitizer (1.6.2)
178 | loofah (~> 2.21)
179 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
180 | railties (7.1.5.2)
181 | actionpack (= 7.1.5.2)
182 | activesupport (= 7.1.5.2)
183 | irb
184 | rackup (>= 1.0.0)
185 | rake (>= 12.2)
186 | thor (~> 1.0, >= 1.2.2)
187 | zeitwerk (~> 2.6)
188 | rake (13.0.6)
189 | rdoc (6.6.3.1)
190 | psych (>= 4.0.0)
191 | reline (0.4.3)
192 | io-console (~> 0.5)
193 | securerandom (0.4.1)
194 | simplecov (0.16.1)
195 | docile (~> 1.1)
196 | json (>= 1.8, < 3)
197 | simplecov-html (~> 0.10.0)
198 | simplecov-html (0.10.2)
199 | sqlite3 (1.4.2)
200 | stringio (3.1.0)
201 | sync (0.5.0)
202 | term-ansicolor (1.7.1)
203 | tins (~> 1.0)
204 | thor (1.4.0)
205 | timeout (0.4.3)
206 | tins (1.28.0)
207 | sync
208 | tzinfo (2.0.6)
209 | concurrent-ruby (~> 1.0)
210 | webrick (1.8.2)
211 | websocket-driver (0.7.5)
212 | websocket-extensions (>= 0.1.0)
213 | websocket-extensions (0.1.5)
214 | zeitwerk (2.6.7)
215 |
216 | PLATFORMS
217 | ruby
218 |
219 | DEPENDENCIES
220 | arask!
221 | coveralls
222 | sqlite3
223 |
224 | BUNDLED WITH
225 | 2.2.15
226 |
--------------------------------------------------------------------------------