command_model 2.0.1 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 894d328023ecf9f0a8935bfe2a198e2fa3d26a55d42b2a4c0178bfa390e9b4bf
4
- data.tar.gz: c00d13c0db81fd1a1c9c49e3ff9fa473d62c0c8131ca449acf8f6dd695109a7d
3
+ metadata.gz: e8cf40c64412f7916aa99c30322b374dc2893635561cb4d7a3a40268795d1f19
4
+ data.tar.gz: 97b8da271006b44b5c5c6ab7ef3db825f7d7696e353dae93c96baa8edbb8e1f9
5
5
  SHA512:
6
- metadata.gz: 016761f5657fd6b00664d0d8e3730d83055506314fa4a49a02194eaa6e7e7f680d8ae234590616a148c31ccc7ab5dfd613b63385121c8e10dafc96adc426cd9b
7
- data.tar.gz: fc0b8d08827f71c8882697eeb2918f9bde7364aecd7f4796e9125727b73ceb0113022427ff76ed1ce96804c624780cc80be23823587828bcf549b6a0cc852d6b
6
+ metadata.gz: 31bfe745e834a943f6221f1fd736ef2e5998ab262d15b4fa621fa733bb6cd2e1f9a9f448e263dd8565da179a766334b0ab983befe784448d9b18b91a24f8b088
7
+ data.tar.gz: 711f2f7069e0c63b1c20fe9a46faf7e737967e6aadc7292b3e40eb64adef217df1014cf199aab1fbf3aa58b462a053c0c8094ae132f26fb03207f303bbfcce1b
@@ -0,0 +1,26 @@
1
+ name: "Ruby CI"
2
+ on:
3
+ push:
4
+ branches: ["master"]
5
+ pull_request:
6
+ branches: ["master"]
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: ['3.2', '3.3']
13
+ gemfile: [ "6.1", "7.0", "7.1" ]
14
+ runs-on: ubuntu-latest
15
+ env:
16
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+ - name: Install Ruby and gems
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
25
+ - name: Run tests
26
+ run: bin/rake
data/.gitignore CHANGED
@@ -3,7 +3,6 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- Gemfile.lock
7
6
  InstalledFiles
8
7
  _yardoc
9
8
  coverage
@@ -15,3 +14,4 @@ spec/reports
15
14
  test/tmp
16
15
  test/version_tmp
17
16
  tmp
17
+ .envrc
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.1
1
+ 3.2.2
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.2.2
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ command_model (2.1.1)
5
+ activemodel (> 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.0.4.3)
11
+ activesupport (= 7.0.4.3)
12
+ activesupport (7.0.4.3)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ concurrent-ruby (1.2.2)
18
+ diff-lcs (1.5.1)
19
+ i18n (1.12.0)
20
+ concurrent-ruby (~> 1.0)
21
+ minitest (5.18.0)
22
+ rake (13.1.0)
23
+ rspec (3.13.0)
24
+ rspec-core (~> 3.13.0)
25
+ rspec-expectations (~> 3.13.0)
26
+ rspec-mocks (~> 3.13.0)
27
+ rspec-core (3.13.0)
28
+ rspec-support (~> 3.13.0)
29
+ rspec-expectations (3.13.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.13.0)
32
+ rspec-mocks (3.13.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.13.0)
35
+ rspec-support (3.13.1)
36
+ tzinfo (2.0.6)
37
+ concurrent-ruby (~> 1.0)
38
+
39
+ PLATFORMS
40
+ arm64-darwin-22
41
+ arm64-darwin-23
42
+ x86_64-linux
43
+
44
+ DEPENDENCIES
45
+ command_model!
46
+ rake (~> 13.1.0)
47
+ rspec (~> 3.13.0)
48
+
49
+ BUNDLED WITH
50
+ 2.4.3
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/jackc/command_model.svg)](https://travis-ci.org/jackc/command_model)
1
+ [![Build Status](https://github.com/jackc/command_model/actions/workflows/ci.yml/badge.svg)](https://github.com/jackc/command_model/actions/workflows/ci.yml)
2
2
 
3
3
  # CommandModel
4
4
 
@@ -14,11 +14,13 @@ to work with once your domain operations become more complex. Domain models
14
14
  usually have richer behavior than can be represented with a typical
15
15
  ActiveRecord style update_attributes.
16
16
 
17
- # yuck!
18
- account.update_attributes balance: account.balance - 50
17
+ ```ruby
18
+ # yuck!
19
+ account.update_attributes balance: account.balance - 50
19
20
 
20
- # much better
21
- account.withdraw amount: 50
21
+ # much better
22
+ account.withdraw amount: 50
23
+ ```
22
24
 
23
25
  But there are multiple complications with the OO approach. How do we integrate
24
26
  Rails style validations? How are user-supplied strings type converted? How do we
@@ -28,27 +30,35 @@ know if the command succeeded? CommandModel solves these problems.
28
30
 
29
31
  Add this line to your application's Gemfile:
30
32
 
31
- gem 'command_model'
33
+ ```ruby
34
+ gem 'command_model'
35
+ ```
32
36
 
33
37
  And then execute:
34
38
 
35
- $ bundle
39
+ ```console
40
+ $ bundle
41
+ ```
36
42
 
37
43
  Or install it yourself as:
38
44
 
39
- $ gem install command_model
45
+ ```console
46
+ $ gem install command_model
47
+ ```
40
48
 
41
49
  ## Usage
42
50
 
43
51
  Create a class derived from CommandModel::Model to represent the command
44
52
  request.
45
53
 
46
- class WithdrawCommand < CommandModel::Model
47
- parameter :amount,
48
- convert: :integer,
49
- presence: true,
50
- numericality: { greater_than: 0, less_than_or_equal_to: 500 }
51
- end
54
+ ```ruby
55
+ class WithdrawCommand < CommandModel::Model
56
+ parameter :amount,
57
+ convert: :integer,
58
+ presence: true,
59
+ numericality: { greater_than: 0, less_than_or_equal_to: 500 }
60
+ end
61
+ ```
52
62
 
53
63
  Create the method to run the command. This method should instantiate and call a new command object. It must pass call
54
64
  a block that actually does the work. The block will only be called if
@@ -57,32 +67,36 @@ any further validations that only can be done during execution. If it adds
57
67
  any errors to the command object then the command will be considered to have
58
68
  failed. Finally, the call method will return self.
59
69
 
60
- class Account
61
- # ...
62
-
63
- def withdraw(args)
64
- WithdrawCommand.new(args).call do |command|
65
- if balance >= command.amount
66
- @balance -= command.amount
67
- else
68
- command.errors.add :amount, "is more than account balance"
69
- end
70
- end
71
- end
70
+ ```ruby
71
+ class Account
72
+ # ...
72
73
 
73
- # ...
74
+ def withdraw(args)
75
+ WithdrawCommand.new(args).call do |command|
76
+ if balance >= command.amount
77
+ @balance -= command.amount
78
+ else
79
+ command.errors.add :amount, "is more than account balance"
80
+ end
74
81
  end
82
+ end
83
+
84
+ # ...
85
+ end
86
+ ```
75
87
 
76
88
  Use example:
77
89
 
78
- response = account.withdraw amount: 50
90
+ ```ruby
91
+ response = account.withdraw amount: 50
79
92
 
80
- if response.success?
81
- puts "Success!"
82
- else
83
- puts "Errors:"
84
- puts response.errors.full_messages
85
- end
93
+ if response.success?
94
+ puts "Success!"
95
+ else
96
+ puts "Errors:"
97
+ puts response.errors.full_messages
98
+ end
99
+ ```
86
100
 
87
101
  ## Mixing in Domain Logic
88
102
 
@@ -93,28 +107,73 @@ method. The execute method is called by the call method if all validations
93
107
  succeed. The following is a reimplementation of the previous example with
94
108
  internal domain logic.
95
109
 
96
- class WithdrawCommand < CommandModel::Model
97
- parameter :amount,
98
- convert: :integer,
99
- presence: true,
100
- numericality: { greater_than: 0, less_than_or_equal_to: 500 }
101
- parameter :account_id, presence: true
102
-
103
- def execute
104
- account = Account.find_by_id account_id
105
- unless account
106
- errors.add :account_id, "not found"
107
- return
108
- end
109
-
110
- if account.balance >= amount
111
- account.balance -= amount
112
- else
113
- errors.add :amount, "is more than account balance"
114
- end
115
- end
110
+ ```ruby
111
+ class WithdrawCommand < CommandModel::Model
112
+ parameter :amount,
113
+ convert: :integer,
114
+ presence: true,
115
+ numericality: { greater_than: 0, less_than_or_equal_to: 500 }
116
+ parameter :account_id, presence: true
117
+
118
+ def execute
119
+ account = Account.find_by_id account_id
120
+ unless account
121
+ errors.add :account_id, "not found"
122
+ return
123
+ end
124
+
125
+ if account.balance >= amount
126
+ account.balance -= amount
127
+ else
128
+ errors.add :amount, "is more than account balance"
129
+ end
130
+ end
131
+ end
132
+ ```
133
+
134
+ ## Dependencies
135
+
136
+ Sometimes a command has requires values that are not supplied by the user. For example, a command may require the
137
+ current user, a database connection, or a logger. These dependencies can be specified with the `dependency` method. The following example adds filtering to ensure that the current user owns the account.
138
+
139
+ ```ruby
140
+ class WithdrawCommand < CommandModel::Model
141
+ dependency :current_user
142
+
143
+ parameter :amount,
144
+ convert: :integer,
145
+ presence: true,
146
+ numericality: { greater_than: 0, less_than_or_equal_to: 500 }
147
+ parameter :account_id, presence: true
148
+
149
+ def execute
150
+ account = current_user.accounts.find_by_id account_id
151
+ unless account
152
+ errors.add :account_id, "not found"
153
+ return
116
154
  end
117
155
 
156
+ if account.balance >= amount
157
+ account.balance -= amount
158
+ else
159
+ errors.add :amount, "is more than account balance"
160
+ end
161
+ end
162
+ end
163
+ ```
164
+
165
+ This command could be called as follows.
166
+
167
+ ```ruby
168
+ WithdrawCommand.execute({amount: 200}, {current_user: current_user})
169
+ ```
170
+
171
+ ## Inheritance
172
+
173
+ Subclasses of `CommandModel::Model` can themselves be subclassed. Parameter and dependency definitions will be copied at
174
+ the time of subclassing. If the superclass is later modified, the parameter and dependency definitions of the subclasses
175
+ will not be modified. This may be changed in the future.
176
+
118
177
  ## Other uses
119
178
 
120
179
  This could be used to wrap database generated errors into normal Rails
@@ -128,8 +187,30 @@ be doing a uniqueness check anyway.
128
187
  There is a simple Rails application in examples/bank that demonstrates the
129
188
  integration of Rails form helpers and validations with CommandModel.
130
189
 
190
+ ## Testing
191
+
192
+ ```console
193
+ $ bundle install
194
+ $ rake
195
+ ```
196
+
197
+ To test against a specific version of Rails / ActiveModel set the BUNDLE_GEMFILE environment variable. For example, to
198
+ test Rails 6.1:
199
+
200
+ ```console
201
+ $ BUNDLE_GEMFILE=gemfiles/6.1.gemfile bundle install
202
+ $ BUNDLE_GEMFILE=gemfiles/6.1.gemfile rake
203
+ ```
204
+
131
205
  ## Version History
132
206
 
207
+ * 2.1.1 - April 8, 2024
208
+ * Dependencies are set before parameters
209
+ * 2.1.0 - March 15, 2024
210
+ * Add dependencies to CommandModel::Model
211
+ * Allow inheritance of CommandModel::Model
212
+ * Require Ruby 3.2+
213
+ * Require Rails / ActiveModel 6.1+
133
214
  * 2.0.1 - April 3, 2023
134
215
  * Date parsing allows 5 digit years
135
216
  * 2.0 - April 11, 2018
data/Rakefile CHANGED
@@ -1,10 +1,7 @@
1
- #!/usr/bin/env rake
1
+ require "bundler/setup"
2
2
  require "bundler/gem_tasks"
3
3
 
4
- begin
5
- require 'rspec/core/rake_task'
6
- RSpec::Core::RakeTask.new(:spec)
7
- rescue LoadError
8
- end
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
9
6
 
10
- task :default => :spec
7
+ task default: :spec
data/bin/rake ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("rake", "rake")
@@ -9,16 +9,15 @@ Gem::Specification.new do |gem|
9
9
  gem.homepage = "https://github.com/JackC/command_model"
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
12
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
13
  gem.name = "command_model"
15
14
  gem.require_paths = ["lib"]
16
15
  gem.version = CommandModel::VERSION
17
16
 
18
- gem.required_ruby_version = '>= 2.5.0'
17
+ gem.required_ruby_version = '>= 3.2.0'
19
18
 
20
- gem.add_dependency 'activemodel', "> 5.0"
19
+ gem.add_dependency 'activemodel', "> 6.1"
21
20
 
22
- gem.add_development_dependency 'rake', "~> 12.3.0"
23
- gem.add_development_dependency 'rspec', "~> 3.7.0"
21
+ gem.add_development_dependency 'rake', "~> 13.1.0"
22
+ gem.add_development_dependency 'rspec', "~> 3.13.0"
24
23
  end
@@ -3,9 +3,9 @@ source 'https://rubygems.org'
3
3
  gem 'rails', '3.2.8'
4
4
 
5
5
  # Bundle edge Rails instead:
6
- # gem 'rails', :git => 'git://github.com/rails/rails.git'
6
+ # gem 'rails', git: 'git://github.com/rails/rails.git'
7
7
 
8
- gem 'command_model', :path => '../..'
8
+ gem 'command_model', path: '../..'
9
9
 
10
10
 
11
11
  # Gems used only for assets and not required
@@ -15,7 +15,7 @@ group :assets do
15
15
  gem 'coffee-rails', '~> 3.2.1'
16
16
 
17
17
  # See https://github.com/sstephenson/execjs#readme for more supported runtimes
18
- # gem 'therubyracer', :platform => :ruby
18
+ # gem 'therubyracer', platform: :ruby
19
19
 
20
20
  gem 'uglifier', '>= 1.0.3'
21
21
  end
@@ -35,4 +35,4 @@ gem 'jquery-rails'
35
35
  # gem 'capistrano'
36
36
 
37
37
  # To use debugger
38
- # gem 'ruby-debug19', :require => 'ruby-debug'
38
+ # gem 'ruby-debug19', require: 'ruby-debug'
@@ -7,44 +7,44 @@
7
7
  @account = Account.find_by_name params[:id]
8
8
  @deposit = Account::DepositCommand.new
9
9
  end
10
-
10
+
11
11
  def deposit
12
12
  @account = Account.find_by_name params[:id]
13
13
  @deposit = @account.deposit params[:deposit]
14
-
14
+
15
15
  if @deposit.success?
16
- redirect_to root_path, :notice => "Deposited #{@deposit.amount} to #{@account.name}'s account."
16
+ redirect_to root_path, notice: "Deposited #{@deposit.amount} to #{@account.name}'s account."
17
17
  else
18
18
  render "deposit_form"
19
19
  end
20
20
  end
21
-
21
+
22
22
  def withdraw_form
23
23
  @account = Account.find_by_name params[:id]
24
24
  @withdraw = Account::WithdrawCommand.new
25
- end
26
-
25
+ end
26
+
27
27
  def withdraw
28
28
  @account = Account.find_by_name params[:id]
29
29
  @withdraw = @account.withdraw params[:withdraw]
30
-
30
+
31
31
  if @withdraw.success?
32
- redirect_to root_path, :notice => "Withdrew #{@withdraw.amount} from #{@account.name}'s account."
32
+ redirect_to root_path, notice: "Withdrew #{@withdraw.amount} from #{@account.name}'s account."
33
33
  else
34
34
  render "withdraw_form"
35
- end
35
+ end
36
36
  end
37
37
 
38
38
  def transfer_form
39
39
  @accounts = Account.all
40
40
  @transfer = Account::TransferCommand.new
41
41
  end
42
-
42
+
43
43
  def transfer
44
44
  @transfer = Account::TransferCommand.new(params[:transfer])
45
-
45
+
46
46
  if @transfer.call.success?
47
- redirect_to root_path, :notice => "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
47
+ redirect_to root_path, notice: "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
48
48
  else
49
49
  @accounts = Account.all
50
50
  render "transfer_form"
@@ -3,12 +3,12 @@ class TransfersController < ApplicationController
3
3
  @accounts = Account.all
4
4
  @transfer = Account::Transfer.new
5
5
  end
6
-
6
+
7
7
  def create
8
8
  @transfer = Account::Transfer.new(params[:transfer])
9
-
9
+
10
10
  if @transfer.call.success?
11
- redirect_to root_path, :notice => "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
11
+ redirect_to root_path, notice: "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
12
12
  else
13
13
  @accounts = Account.all
14
14
  render :new
@@ -12,12 +12,8 @@
12
12
  </ul>
13
13
  <% end %>
14
14
 
15
- <%= form_for @deposit, :as => :deposit, :url => account_deposit_path(@account) do |f| %>
15
+ <%= form_for @deposit, as: :deposit, url: account_deposit_path(@account) do |f| %>
16
16
  <%= f.label :amount %>
17
17
  <%= f.text_field :amount %>
18
18
  <%= f.submit "Deposit" %>
19
19
  <% end %>
20
-
21
-
22
-
23
-
@@ -12,12 +12,8 @@
12
12
  </ul>
13
13
  <% end %>
14
14
 
15
- <%= form_for @withdraw, :as => :withdraw, :url => account_withdraw_path(@account) do |f| %>
15
+ <%= form_for @withdraw, as: :withdraw, url: account_withdraw_path(@account) do |f| %>
16
16
  <%= f.label :amount %>
17
17
  <%= f.text_field :amount %>
18
18
  <%= f.submit "Deposit" %>
19
19
  <% end %>
20
-
21
-
22
-
23
-
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Bank</title>
5
- <%= stylesheet_link_tag "application", :media => "all" %>
5
+ <%= stylesheet_link_tag "application", media: "all" %>
6
6
  <%= javascript_include_tag "application" %>
7
7
  <%= csrf_meta_tags %>
8
8
  </head>
@@ -14,11 +14,11 @@
14
14
  <%= form_for @transfer do |f| %>
15
15
  <div>
16
16
  <%= f.label :from_name %><br />
17
- <%= f.select :from_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, :selected => f.object.from_name, :include_blank => true %>
17
+ <%= f.select :from_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, selected: f.object.from_name, include_blank: true %>
18
18
  </div>
19
19
  <div>
20
20
  <%= f.label :to_name %><br />
21
- <%= f.select :to_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, :selected => f.object.to_name, :include_blank => true %>
21
+ <%= f.select :to_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, selected: f.object.to_name, include_blank: true %>
22
22
  </div>
23
23
  <div>
24
24
  <%= f.label :amount %><br />
@@ -26,7 +26,3 @@
26
26
  </div>
27
27
  <%= f.submit "Transfer" %>
28
28
  <% end %>
29
-
30
-
31
-
32
-
@@ -10,7 +10,7 @@ require "rails/test_unit/railtie"
10
10
 
11
11
  if defined?(Bundler)
12
12
  # If you precompile assets before deploying to production, use this line
13
- Bundler.require(*Rails.groups(:assets => %w(development test)))
13
+ Bundler.require(*Rails.groups(assets: %w(development test)))
14
14
  # If you want your assets lazily compiled in production, use this line
15
15
  # Bundler.require(:default, :assets, Rails.env)
16
16
  end
@@ -1,11 +1,11 @@
1
1
  Bank::Application.routes.draw do
2
- get "accounts/:id/withdraw" => "accounts#withdraw_form", :as => :account_withdraw_form
3
- post "accounts/:id/withdraw" => "accounts#withdraw", :as => :account_withdraw
4
-
5
- get "accounts/:id/deposit" => "accounts#deposit_form", :as => :account_deposit_form
6
- post "accounts/:id/deposit" => "accounts#deposit", :as => :account_deposit
2
+ get "accounts/:id/withdraw" => "accounts#withdraw_form", as: :account_withdraw_form
3
+ post "accounts/:id/withdraw" => "accounts#withdraw", as: :account_withdraw
4
+
5
+ get "accounts/:id/deposit" => "accounts#deposit_form", as: :account_deposit_form
6
+ post "accounts/:id/deposit" => "accounts#deposit", as: :account_deposit
7
7
 
8
8
  resources :transfers, only: %w[new create]
9
9
 
10
- root :to => "accounts#index"
10
+ root to: "accounts#index"
11
11
  end
@@ -3,8 +3,8 @@ require 'rails/performance_test_help'
3
3
 
4
4
  class BrowsingTest < ActionDispatch::PerformanceTest
5
5
  # Refer to the documentation for all available options
6
- # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
7
- # :output => 'tmp/performance', :formats => [:flat] }
6
+ # self.profile_options = { runs: 5, metrics: [:wall_time, :memory]
7
+ # output: 'tmp/performance', formats: [:flat] }
8
8
 
9
9
  def test_homepage
10
10
  get '/'
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "activemodel", "~> 5.0.0"
3
+ gem "activemodel", "~> 6.1.0"
4
4
 
5
5
  gemspec :path=>"../"
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ command_model (2.1.1)
5
+ activemodel (> 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.1.7.7)
11
+ activesupport (= 6.1.7.7)
12
+ activesupport (6.1.7.7)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ zeitwerk (~> 2.3)
18
+ concurrent-ruby (1.2.3)
19
+ diff-lcs (1.5.1)
20
+ i18n (1.14.4)
21
+ concurrent-ruby (~> 1.0)
22
+ minitest (5.22.3)
23
+ rake (13.1.0)
24
+ rspec (3.13.0)
25
+ rspec-core (~> 3.13.0)
26
+ rspec-expectations (~> 3.13.0)
27
+ rspec-mocks (~> 3.13.0)
28
+ rspec-core (3.13.0)
29
+ rspec-support (~> 3.13.0)
30
+ rspec-expectations (3.13.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.13.0)
33
+ rspec-mocks (3.13.0)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.13.0)
36
+ rspec-support (3.13.1)
37
+ tzinfo (2.0.6)
38
+ concurrent-ruby (~> 1.0)
39
+ zeitwerk (2.6.13)
40
+
41
+ PLATFORMS
42
+ arm64-darwin-23
43
+ x86_64-linux
44
+
45
+ DEPENDENCIES
46
+ activemodel (~> 6.1.0)
47
+ command_model!
48
+ rake (~> 13.1.0)
49
+ rspec (~> 3.13.0)
50
+
51
+ BUNDLED WITH
52
+ 2.4.3
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "activemodel", "~> 5.1.0"
3
+ gem "activemodel", "~> 7.0.0"
4
4
 
5
5
  gemspec :path=>"../"
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ command_model (2.1.1)
5
+ activemodel (> 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.0.4.3)
11
+ activesupport (= 7.0.4.3)
12
+ activesupport (7.0.4.3)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ concurrent-ruby (1.2.3)
18
+ diff-lcs (1.5.1)
19
+ i18n (1.14.4)
20
+ concurrent-ruby (~> 1.0)
21
+ minitest (5.22.3)
22
+ rake (13.1.0)
23
+ rspec (3.13.0)
24
+ rspec-core (~> 3.13.0)
25
+ rspec-expectations (~> 3.13.0)
26
+ rspec-mocks (~> 3.13.0)
27
+ rspec-core (3.13.0)
28
+ rspec-support (~> 3.13.0)
29
+ rspec-expectations (3.13.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.13.0)
32
+ rspec-mocks (3.13.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.13.0)
35
+ rspec-support (3.13.1)
36
+ tzinfo (2.0.6)
37
+ concurrent-ruby (~> 1.0)
38
+
39
+ PLATFORMS
40
+ arm64-darwin-23
41
+ x86_64-linux
42
+
43
+ DEPENDENCIES
44
+ activemodel (~> 7.0.0)
45
+ command_model!
46
+ rake (~> 13.1.0)
47
+ rspec (~> 3.13.0)
48
+
49
+ BUNDLED WITH
50
+ 2.4.3
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "activemodel", "~> 7.1.0"
4
+
5
+ gemspec :path=>"../"
@@ -0,0 +1,60 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ command_model (2.1.1)
5
+ activemodel (> 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.1.3.2)
11
+ activesupport (= 7.1.3.2)
12
+ activesupport (7.1.3.2)
13
+ base64
14
+ bigdecimal
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ connection_pool (>= 2.2.5)
17
+ drb
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ mutex_m
21
+ tzinfo (~> 2.0)
22
+ base64 (0.2.0)
23
+ bigdecimal (3.1.7)
24
+ concurrent-ruby (1.2.3)
25
+ connection_pool (2.4.1)
26
+ diff-lcs (1.5.1)
27
+ drb (2.2.1)
28
+ i18n (1.14.4)
29
+ concurrent-ruby (~> 1.0)
30
+ minitest (5.22.3)
31
+ mutex_m (0.2.0)
32
+ rake (13.1.0)
33
+ rspec (3.13.0)
34
+ rspec-core (~> 3.13.0)
35
+ rspec-expectations (~> 3.13.0)
36
+ rspec-mocks (~> 3.13.0)
37
+ rspec-core (3.13.0)
38
+ rspec-support (~> 3.13.0)
39
+ rspec-expectations (3.13.0)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.13.0)
42
+ rspec-mocks (3.13.0)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.13.0)
45
+ rspec-support (3.13.1)
46
+ tzinfo (2.0.6)
47
+ concurrent-ruby (~> 1.0)
48
+
49
+ PLATFORMS
50
+ arm64-darwin-23
51
+ x86_64-linux
52
+
53
+ DEPENDENCIES
54
+ activemodel (~> 7.1.0)
55
+ command_model!
56
+ rake (~> 13.1.0)
57
+ rspec (~> 3.13.0)
58
+
59
+ BUNDLED WITH
60
+ 2.4.3
@@ -4,7 +4,12 @@ module CommandModel
4
4
  include ActiveModel::Conversion
5
5
  extend ActiveModel::Naming
6
6
 
7
- Parameter = Struct.new(:name, :converters, :validations)
7
+ def self.inherited(subclass)
8
+ subclass.instance_variable_set :@parameters, parameters.dup.freeze
9
+ subclass.instance_variable_set :@dependencies, dependencies.dup.freeze
10
+ end
11
+
12
+ Parameter = Data.define(:name, :converters, :validations)
8
13
 
9
14
  # Parameter requires one or more attributes as its first parameter(s).
10
15
  # It accepts an options hash as its last parameter.
@@ -26,11 +31,12 @@ module CommandModel
26
31
  # parameter :height, :weight,
27
32
  # convert: [CommandModel::Convert::StringMutator.new { |s| s.gsub(",", "")}, :integer],
28
33
  # presence: true,
29
- # numericality: { :greater_than_or_equal_to => 0 }
34
+ # numericality: { greater_than_or_equal_to: 0 }
30
35
  def self.parameter(*args)
31
36
  options = args.last.kind_of?(Hash) ? args.pop.clone : {}
32
37
  converters = options.delete(:convert)
33
38
 
39
+ @parameters ||= [].freeze
34
40
  args.each do |name|
35
41
  attr_reader name
36
42
 
@@ -40,13 +46,13 @@ module CommandModel
40
46
  attr_writer name
41
47
  end
42
48
  validates name, options.clone if options.present? # clone options because validates mutates the hash :(
43
- parameters.push Parameter.new name, converters, options
49
+ @parameters = (@parameters + [Parameter.new(name, converters, options)]).freeze
44
50
  end
45
51
  end
46
52
 
47
53
  # Returns array of all parameters defined for class
48
54
  def self.parameters
49
- @parameters ||= []
55
+ @parameters ||= [].freeze
50
56
  end
51
57
 
52
58
  def self.attr_type_converting_writer(name, converters) #:nodoc
@@ -82,6 +88,38 @@ module CommandModel
82
88
  end
83
89
  end
84
90
 
91
+ Dependency = Data.define(:name, :default, :allow_blank)
92
+
93
+ # Dependency requires one or more attributes as its first parameter(s). A dependency is something that is required
94
+ # for the command to execute that is not user supplied input. For example, a database connection, a logger, or the
95
+ # current user.
96
+ #
97
+ # ==== Keyword Arguments
98
+ #
99
+ # * default - An object that will be used as the default value for the dependency or a callable object that will be
100
+ # called to get the default value.
101
+ # * allow_blank - If true, the dependency can be nil or blank. If false, the dependency must be present.
102
+ #
103
+ # ==== Examples
104
+ #
105
+ # dependency :current_user
106
+ # dependency :stdout, default: -> { $stdout }
107
+ def self.dependency(*names, default: nil, allow_blank: false)
108
+ @dependencies ||= [].freeze
109
+ names.each do |name|
110
+ name = name.to_sym
111
+ attr_reader name
112
+ private attr_writer name
113
+ default_callable = default.respond_to?(:call) ? default : -> { default }
114
+ @dependencies = (@dependencies + [Dependency.new(name, default_callable, allow_blank)]).freeze
115
+ end
116
+ end
117
+
118
+ # Returns array of all dependencies defined for class.
119
+ def self.dependencies
120
+ @dependencies ||= [].freeze
121
+ end
122
+
85
123
  # Executes a block of code if the command model is valid.
86
124
  #
87
125
  # Accepts either a command model or a hash of attributes with which to
@@ -89,18 +127,19 @@ module CommandModel
89
127
  #
90
128
  # ==== Examples
91
129
  #
92
- # RenameUserCommand.execute(:login => "john") do |command|
130
+ # RenameUserCommand.execute(login: "john") do |command|
93
131
  # if allowed_to_rename_user?
94
132
  # self.login = command.login
95
133
  # else
96
134
  # command.errors.add :base, "not allowed to rename"
97
135
  # end
98
136
  # end
99
- def self.execute(attributes_or_command, &block)
137
+ def self.execute(attributes_or_command, dependencies={}, &block)
100
138
  command = if attributes_or_command.kind_of? self
139
+ raise ArgumentError, "cannot pass dependencies with already initialized command" if dependencies.present?
101
140
  attributes_or_command
102
141
  else
103
- new(attributes_or_command)
142
+ new(attributes_or_command, dependencies)
104
143
  end
105
144
 
106
145
  command.call &block
@@ -129,7 +168,21 @@ module CommandModel
129
168
  # Accepts a parameters hash or another of the same class. If another
130
169
  # instance of the same class is passed in then the parameters are copied
131
170
  # to the new object.
132
- def initialize(parameters={})
171
+ def initialize(parameters={}, dependencies={})
172
+ dependencies = dependencies.symbolize_keys
173
+ self.class.dependencies.each do |dependency|
174
+ value = dependencies.fetch(dependency.name, dependency.default.call)
175
+ if value.blank? && !dependency.allow_blank
176
+ raise ArgumentError, "Dependency #{dependency.name} cannot be blank"
177
+ end
178
+ self.send "#{dependency.name}=", dependencies.fetch(dependency.name, dependency.default.call)
179
+ end
180
+
181
+ unknown_dependencies = dependencies.keys - self.class.dependencies.map(&:name)
182
+ if unknown_dependencies.present?
183
+ raise ArgumentError, "Unknown dependencies: #{bad_dependencies.join(", ")}"
184
+ end
185
+
133
186
  @type_conversion_errors = {}
134
187
  set_parameters parameters
135
188
  end
@@ -1,3 +1,3 @@
1
1
  module CommandModel
2
- VERSION = "2.0.1"
2
+ VERSION = "2.1.1"
3
3
  end
data/spec/model_spec.rb CHANGED
@@ -6,7 +6,7 @@ class ExampleCommand < CommandModel::Model
6
6
  end
7
7
 
8
8
  describe CommandModel::Model do
9
- let(:example_command) { ExampleCommand.new :name => "John" }
9
+ let(:example_command) { ExampleCommand.new name: "John" }
10
10
  let(:invalid_example_command) { ExampleCommand.new }
11
11
 
12
12
  describe "self.parameter" do
@@ -38,7 +38,7 @@ describe CommandModel::Model do
38
38
  end
39
39
 
40
40
  it "accepts multiple attributes with convert" do
41
- klass.parameter :foo, :bar, :convert => :integer
41
+ klass.parameter :foo, :bar, convert: :integer
42
42
  expect(klass.new.methods).to include(:foo)
43
43
  expect(klass.new.methods).to include(:foo=)
44
44
  expect(klass.new.methods).to include(:bar)
@@ -46,7 +46,7 @@ describe CommandModel::Model do
46
46
  end
47
47
 
48
48
  it "accepts multiple attributes with validation" do
49
- klass.parameter :foo, :bar, :presence => true
49
+ klass.parameter :foo, :bar, presence: true
50
50
  expect(klass.new.methods).to include(:foo)
51
51
  expect(klass.new.methods).to include(:foo=)
52
52
  expect(klass.new.methods).to include(:bar)
@@ -72,6 +72,27 @@ describe CommandModel::Model do
72
72
  expect(instance).to_not be_valid
73
73
  expect(instance.errors[:name]).to be_present
74
74
  end
75
+
76
+ it "works when model is inherited" do
77
+ klass.parameter :foo
78
+ expect(klass.parameters.map(&:name)).to eq([:foo])
79
+
80
+ klass_b = Class.new(klass)
81
+ expect(klass_b.parameters.map(&:name)).to eq([:foo])
82
+ klass_b.parameter :bar
83
+ expect(klass.parameters.map(&:name)).to eq([:foo])
84
+ expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
85
+
86
+ klass_c = Class.new(klass_b)
87
+ expect(klass.parameters.map(&:name)).to eq([:foo])
88
+ expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
89
+ expect(klass_c.parameters.map(&:name)).to eq([:foo, :bar])
90
+
91
+ klass_c.parameter :baz
92
+ expect(klass.parameters.map(&:name)).to eq([:foo])
93
+ expect(klass_b.parameters.map(&:name)).to eq([:foo, :bar])
94
+ expect(klass_c.parameters.map(&:name)).to eq([:foo, :bar, :baz])
95
+ end
75
96
  end
76
97
 
77
98
  describe "self.parameters" do
@@ -89,13 +110,65 @@ describe CommandModel::Model do
89
110
  end
90
111
  end
91
112
 
113
+ describe "self.dependency" do
114
+ let(:klass) { Class.new(CommandModel::Model) }
115
+
116
+ it "creates an attribute reader" do
117
+ klass.dependency :foo, allow_blank: true
118
+ expect(klass.new.methods).to include(:foo)
119
+ end
120
+
121
+ it "accepts multiple attributes" do
122
+ klass.dependency :foo, :bar, allow_blank: true
123
+ expect(klass.new.methods).to include(:foo)
124
+ expect(klass.new.methods).to include(:bar)
125
+ end
126
+
127
+ it "accepts multiple attributes with default" do
128
+ klass.dependency :foo, :bar, default: -> { "baz" }
129
+ expect(klass.new.methods).to include(:foo)
130
+ expect(klass.new.methods).to include(:bar)
131
+ end
132
+
133
+ it "works when model is inherited" do
134
+ klass.dependency :foo
135
+ expect(klass.dependencies.map(&:name)).to eq([:foo])
136
+
137
+ klass_b = Class.new(klass)
138
+ expect(klass_b.dependencies.map(&:name)).to eq([:foo])
139
+ klass_b.dependency :bar
140
+ expect(klass.dependencies.map(&:name)).to eq([:foo])
141
+ expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
142
+
143
+ klass_c = Class.new(klass_b)
144
+ expect(klass.dependencies.map(&:name)).to eq([:foo])
145
+ expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
146
+ expect(klass_c.dependencies.map(&:name)).to eq([:foo, :bar])
147
+
148
+ klass_c.dependency :baz
149
+ expect(klass.dependencies.map(&:name)).to eq([:foo])
150
+ expect(klass_b.dependencies.map(&:name)).to eq([:foo, :bar])
151
+ expect(klass_c.dependencies.map(&:name)).to eq([:foo, :bar, :baz])
152
+ end
153
+ end
154
+
155
+ describe "self.dependencies" do
156
+ it "returns all dependencies in class" do
157
+ klass = Class.new(CommandModel::Model)
158
+ klass.dependency :foo
159
+ klass.dependency :bar
160
+
161
+ expect(klass.dependencies.map(&:name)).to eq([:foo, :bar])
162
+ end
163
+ end
164
+
92
165
  describe "self.execute" do
93
166
  it "accepts object of same kind and returns it" do
94
167
  expect(ExampleCommand.execute(example_command) {}).to eq(example_command)
95
168
  end
96
169
 
97
170
  it "accepts attributes, creates object, and returns it" do
98
- c = ExampleCommand.execute(:name => "John") {}
171
+ c = ExampleCommand.execute(name: "John") {}
99
172
  expect(c).to be_kind_of(ExampleCommand)
100
173
  expect(c.name).to eq("John")
101
174
  end
@@ -129,6 +202,25 @@ describe CommandModel::Model do
129
202
 
130
203
  expect(example_command).to_not be_success
131
204
  end
205
+
206
+ it "uses default dependencies when not provided" do
207
+ klass = Class.new(CommandModel::Model)
208
+ klass.dependency :stdout, default: -> { $stdout }
209
+ klass.parameter :name
210
+ m = klass.execute(name: "John")
211
+ expect(m.stdout).to eq($stdout)
212
+ expect(m.execution_attempted?).to eq(true)
213
+ end
214
+
215
+ it "accepts dependencies from arguments" do
216
+ klass = Class.new(CommandModel::Model)
217
+ klass.dependency :stdout, default: -> { $stdout }
218
+ klass.parameter :name
219
+ writer = StringIO.new
220
+ m = klass.execute({name: "John"}, stdout: writer)
221
+ expect(m.stdout).to eq(writer)
222
+ expect(m.execution_attempted?).to eq(true)
223
+ end
132
224
  end
133
225
 
134
226
  describe "self.success" do
@@ -151,15 +243,46 @@ describe CommandModel::Model do
151
243
 
152
244
  describe "initialize" do
153
245
  it "assigns parameters from hash" do
154
- m = ExampleCommand.new :name => "John"
246
+ m = ExampleCommand.new name: "John"
155
247
  expect(m.name).to eq("John")
156
248
  end
157
249
 
158
250
  it "assigns parameters from other CommandModel" do
159
- other = ExampleCommand.new :name => "John"
251
+ other = ExampleCommand.new name: "John"
160
252
  m = ExampleCommand.new other
161
253
  expect(m.name).to eq(other.name)
162
254
  end
255
+
256
+ it "assigns default dependencies when not provided" do
257
+ klass = Class.new(CommandModel::Model)
258
+ klass.dependency :stdout, default: -> { $stdout }
259
+ klass.parameter :name
260
+ m = klass.new name: "John"
261
+ expect(m.stdout).to eq($stdout)
262
+ end
263
+
264
+ it "assigns dependencies from arguments" do
265
+ klass = Class.new(CommandModel::Model)
266
+ klass.dependency :stdout, default: -> { $stdout }
267
+ klass.parameter :name
268
+ writer = StringIO.new
269
+ m = klass.new({name: "John"}, stdout: writer)
270
+ expect(m.stdout).to eq(writer)
271
+ end
272
+
273
+ it "raises error when dependency is missing" do
274
+ klass = Class.new(CommandModel::Model)
275
+ klass.dependency :stdout
276
+ klass.parameter :name
277
+ expect { klass.new name: "John" }.to raise_error(StandardError)
278
+ end
279
+
280
+ it "does not raise error when allow blank dependency is missing" do
281
+ klass = Class.new(CommandModel::Model)
282
+ klass.dependency :stdout, allow_blank: true
283
+ klass.parameter :name
284
+ expect { klass.new name: "John" }.to_not raise_error
285
+ end
163
286
  end
164
287
 
165
288
  describe "call" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jack Christensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-03 00:00:00.000000000 Z
11
+ date: 2024-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 12.3.0
33
+ version: 13.1.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 12.3.0
40
+ version: 13.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.7.0
47
+ version: 3.13.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.7.0
54
+ version: 3.13.0
55
55
  description: CommandModel - when update_attributes isn't enough.
56
56
  email:
57
57
  - jack@jackchristensen.com
@@ -59,14 +59,17 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
+ - ".github/workflows/ci.yml"
62
63
  - ".gitignore"
63
64
  - ".rspec"
64
65
  - ".ruby-version"
65
- - ".travis.yml"
66
+ - ".tool-versions"
66
67
  - Gemfile
68
+ - Gemfile.lock
67
69
  - LICENSE
68
70
  - README.md
69
71
  - Rakefile
72
+ - bin/rake
70
73
  - command_model.gemspec
71
74
  - examples/bank/.gitignore
72
75
  - examples/bank/Gemfile
@@ -128,8 +131,12 @@ files:
128
131
  - examples/bank/vendor/assets/javascripts/.gitkeep
129
132
  - examples/bank/vendor/assets/stylesheets/.gitkeep
130
133
  - examples/bank/vendor/plugins/.gitkeep
131
- - gemfiles/5.0.gemfile
132
- - gemfiles/5.1.gemfile
134
+ - gemfiles/6.1.gemfile
135
+ - gemfiles/6.1.gemfile.lock
136
+ - gemfiles/7.0.gemfile
137
+ - gemfiles/7.0.gemfile.lock
138
+ - gemfiles/7.1.gemfile
139
+ - gemfiles/7.1.gemfile.lock
133
140
  - lib/command_model.rb
134
141
  - lib/command_model/convert.rb
135
142
  - lib/command_model/model.rb
@@ -148,14 +155,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
155
  requirements:
149
156
  - - ">="
150
157
  - !ruby/object:Gem::Version
151
- version: 2.5.0
158
+ version: 3.2.0
152
159
  required_rubygems_version: !ruby/object:Gem::Requirement
153
160
  requirements:
154
161
  - - ">="
155
162
  - !ruby/object:Gem::Version
156
163
  version: '0'
157
164
  requirements: []
158
- rubygems_version: 3.4.1
165
+ rubygems_version: 3.4.10
159
166
  signing_key:
160
167
  specification_version: 4
161
168
  summary: CommandModel integrates Rails validations with command objects. This allows
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.5.0
4
- gemfile:
5
- - gemfiles/5.0.gemfile
6
- - gemfiles/5.1.gemfile