simple_state_machine 0.5.2 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +46 -0
  3. data/.gitignore +3 -0
  4. data/.travis.yml +17 -0
  5. data/Changelog.rdoc +16 -0
  6. data/Gemfile +7 -0
  7. data/README.rdoc +154 -99
  8. data/examples/conversation.rb +5 -5
  9. data/examples/lamp.rb +5 -5
  10. data/examples/relationship.rb +8 -8
  11. data/examples/traffic_light.rb +3 -3
  12. data/examples/user.rb +8 -4
  13. data/gemfiles/Gemfile.activerecord-5.2.x +9 -0
  14. data/gemfiles/Gemfile.activerecord-6.0.x +9 -0
  15. data/gemfiles/Gemfile.activerecord-6.1.x +8 -0
  16. data/gemfiles/Gemfile.activerecord-main.x +9 -0
  17. data/gemfiles/Gemfile.basic +6 -0
  18. data/lib/simple_state_machine/.DS_Store +0 -0
  19. data/lib/simple_state_machine/active_record.rb +2 -64
  20. data/lib/simple_state_machine/decorator/active_record.rb +68 -0
  21. data/lib/simple_state_machine/decorator/default.rb +91 -0
  22. data/lib/simple_state_machine/railtie.rb +1 -1
  23. data/lib/simple_state_machine/simple_state_machine.rb +8 -251
  24. data/lib/simple_state_machine/state_machine.rb +88 -0
  25. data/lib/simple_state_machine/state_machine_definition.rb +72 -0
  26. data/lib/simple_state_machine/tools/graphviz.rb +21 -0
  27. data/lib/simple_state_machine/tools/inspector.rb +44 -0
  28. data/lib/simple_state_machine/transition.rb +40 -0
  29. data/lib/simple_state_machine/version.rb +1 -1
  30. data/lib/simple_state_machine.rb +13 -3
  31. data/lib/tasks/graphviz.rake +31 -0
  32. data/simple_state_machine.gemspec +14 -24
  33. data/spec/.DS_Store +0 -0
  34. data/spec/active_record_spec.rb +216 -179
  35. data/spec/{decorator_spec.rb → decorator/default_spec.rb} +32 -32
  36. data/spec/examples_spec.rb +17 -17
  37. data/spec/mountable_spec.rb +26 -14
  38. data/spec/simple_state_machine_spec.rb +128 -92
  39. data/spec/spec_helper.rb +18 -5
  40. data/spec/state_machine_definition_spec.rb +48 -34
  41. data/spec/state_machine_spec.rb +36 -2
  42. data/spec/tools/graphviz_spec.rb +30 -0
  43. data/spec/tools/inspector_spec.rb +70 -0
  44. metadata +54 -128
  45. data/autotest/discover.rb +0 -1
  46. data/lib/tasks/graphiz.rake +0 -13
  47. data/rails/graphiz.rake +0 -16
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4cf708bed33ca00037b1fbb2562b2a4c351666d82a4555b84078600b9e90ad03
4
+ data.tar.gz: 251e24c03f5c59313aec334045670ed024c2720630c188d17bfed1eced1827be
5
+ SHA512:
6
+ metadata.gz: 482b1ba0a9e91260dfe56153453b636640dcd7c37916fd692e13d8607f59ee141d7161c9db6e9a50cdbb14b21b2895227129edf1c4f35dbcb733caceafeb8beb
7
+ data.tar.gz: 5c3b05eb49e792a4289e85c5be1f10f9239020a0147e0ab5b617bba58d7fac4b727a47f45564c472e25e4079e8d1fb7d52838f9a8af9dd610a90e2580d6a9132
@@ -0,0 +1,46 @@
1
+ name: Build
2
+ on:
3
+ - push
4
+ - pull_request
5
+
6
+ jobs:
7
+ build:
8
+ name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }}
9
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ ruby:
14
+ - "3.0"
15
+ - "2.7"
16
+ - "2.6"
17
+ - "2.5"
18
+ rails:
19
+ - "5.2"
20
+ - "6.0"
21
+ - "6.1"
22
+ - main
23
+ exclude:
24
+ - ruby: 2.5
25
+ rails: main
26
+ - ruby: 2.6
27
+ rails: main
28
+ - ruby: 3.0
29
+ rails: "5.1"
30
+ - ruby: 3.0
31
+ rails: "5.2"
32
+
33
+ runs-on: 'ubuntu-latest'
34
+
35
+ env:
36
+ BUNDLE_GEMFILE: gemfiles/Gemfile.activerecord-${{ matrix.rails }}.x
37
+
38
+ steps:
39
+ - uses: actions/checkout@v2
40
+ - uses: ruby/setup-ruby@v1
41
+ with:
42
+ ruby-version: ${{ matrix.ruby }}
43
+ - name: Setup project
44
+ run: bundle install
45
+ - name: Run test
46
+ run: bundle exec rspec spec
data/.gitignore CHANGED
@@ -1 +1,4 @@
1
1
  *.swp
2
+ .bundle
3
+ .ruby-version
4
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
4
+ - 2.7
5
+ - 3.0
6
+ - jruby-9.2.16.0
7
+ script: bundle exec rspec spec
8
+
9
+ gemfile:
10
+ - gemfiles/Gemfile.activerecord-6.0.x
11
+ - gemfiles/Gemfile.activerecord-6.1.x
12
+ - gemfiles/Gemfile.basic
13
+
14
+ matrix:
15
+ exclude:
16
+ - rvm: jruby
17
+ gemfile: gemfiles/Gemfile.activerecord-4.2.x
data/Changelog.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ == 0.6.0
2
+ === Enhancements
3
+ - Define decorated methods as #{event_name}_with_managed_state instead of with_managed_state_#{event_name} [Petrik]
4
+ - Added raised_error method to access caught Errors [Petrik]
5
+ - Added support for a default error state [Marek de Heus]
6
+ - Removed transaction support, you can still add it manually, see active_record_spec.rb [Marek de Heus]
7
+ - Allow catching errors for subclasses of the error [Petrik]
8
+ - Added gem install instructions [Marek de Heus]
9
+ - Added define_event method to simplify mountable state machine definitions [Petrik]
10
+ - Added end_states method so we can check the state machine correctness [Petrik]
11
+ - Added begin_states method so we can check the state machine correctness [Petrik]
12
+
13
+ === Bugfixes
14
+ - Fixed bug in Inspector, from state can now be a Error class [Marek de Heus]
15
+ - Make sure from and end states are uniq [Petrik]
16
+ - fixed typos (graphiz -> graphviz) (redmar-master) [rjk]
data/Gemfile CHANGED
@@ -2,3 +2,10 @@
2
2
  source "http://rubygems.org"
3
3
 
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "rspec", "~> 3.0"
8
+ gem "activerecord", ">= 5.2.0"
9
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
10
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
11
+ end
data/README.rdoc CHANGED
@@ -1,43 +1,29 @@
1
1
  = SimpleStateMachine
2
2
 
3
+ {<img src="https://github.com/mdh/ssm/actions/workflows/build.yml/badge.svg" />}[https://github.com/mdh/ssm/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++]
4
+
3
5
  A simple DSL to decorate existing methods with state transition guards.
4
6
 
5
7
  Instead of using a DSL to define events, SimpleStateMachine decorates methods
6
8
  to help you encapsulate state and guard state transitions.
7
9
 
8
- It supports exception rescuing, google chart visualization and mountable state_machines.
9
-
10
- == Basic example
11
-
12
- class LampSwitch
13
-
14
- extend SimpleStateMachine
10
+ It supports exception rescuing, google chart visualization and mountable state machines.
15
11
 
16
- def initialize
17
- self.state = 'off'
18
- end
12
+ == Usage
19
13
 
20
- def push_switch
21
- puts "pushed switch"
22
- end
23
- event :push_switch, :off => :on,
24
- :on => :off
14
+ Define an event and specify how the state should transition. If we want the state to change
15
+ from *pending* to *active* we write:
25
16
 
26
- end
27
-
28
- lamp = LampSwitch.new
29
- lamp.state # => 'off'
30
- lamp.off? # => true
31
- lamp.push_switch # => 'pushed switch'
32
- lamp.state # => 'on'
33
- lamp.on? # => true
34
- lamp.push_switch # => 'pushed switch'
35
- lamp.off? # => true
17
+ event :activate_account, :pending => :active
36
18
 
19
+ That's it. You can now call *activate_account* and the state will automatically change.
20
+ If the state change is not allowed, a SimpleStateMachine::IllegalStateTransitionError is
21
+ raised.
37
22
 
38
- == Basic usage
23
+ === Methods with arguments
39
24
 
40
- Define your event as a method, arguments are allowed:
25
+ If you want to pass arguments and call other methods before the state transition, define your
26
+ event as a method.
41
27
 
42
28
  def activate_account(activation_code)
43
29
  # call other methods, no need to add these in callbacks
@@ -45,119 +31,187 @@ Define your event as a method, arguments are allowed:
45
31
  end
46
32
 
47
33
  Now mark the method as an event and specify how the state should transition
48
- when the method is called. If we want the state to change from :pending to :active we write:
34
+ when the method is called.
49
35
 
50
36
  event :activate_account, :pending => :active
51
37
 
52
- That's it!
53
- You can now call activate_account and the state will automatically change.
54
- If the state change is not allowed, a SimpleStateMachine::IllegalStateTransitionError is raised.
55
38
 
56
- === Using ActiveRecord / ActiveModel validations
57
- When using ActiveRecord / ActiveModel you can add an error to the errors object.
58
- This will prevent the state from being changed.
59
-
60
- def activate_account(activation_code)
61
- if activation_code_invalid?(activation_code)
62
- errors.add(:activation_code, 'Invalid')
63
- end
64
- end
65
39
 
66
- activate_account!("INVALID_CODE") # => ActiveRecord::RecordInvalid, "Validation failed: Activation code is invalid"
40
+ == Basic example
67
41
 
68
- === Catching exceptions
69
- You can rescue exceptions and specify the failure state
42
+ class LampSwitch
43
+
44
+ extend SimpleStateMachine
45
+
46
+ def initialize
47
+ self.state = 'off'
48
+ end
49
+
50
+ event :push_switch, :off => :on,
51
+ :on => :off
70
52
 
71
- def download_data
72
- Service.download_data
73
53
  end
74
- event :download_data, :pending => :downloaded,
75
- Service::ConnectionError => :download_failed
76
54
 
77
- download_data! # catches Service::ConnectionError
78
- state # => "download_failed"
55
+ lamp = LampSwitch.new
56
+ lamp.state # => 'off'
57
+ lamp.off? # => true
58
+ lamp.push_switch #
59
+ lamp.state # => 'on'
60
+ lamp.on? # => true
61
+ lamp.push_switch #
62
+ lamp.off? # => true
79
63
 
80
- === Catching all from states
81
- If an event should transition from all states you can use :all
82
64
 
83
- event :suspend, :all => :suspended
65
+ == ActiveRecord
84
66
 
85
- == ActiveRecord Example
67
+ For ActiveRecord methods are decorated with state transition guards _and_ persistence.
68
+ Methods marked as events behave like ActiveRecord *save* and *save!*.
86
69
 
87
- To add a state machine with ActiveRecord persistence:
88
- - extend SimpleStateMachine::ActiveRecord,
89
- - set the initial state in after_initialize,
90
- - turn methods into events
70
+ === Example
71
+
72
+ To add a state machine to an ActiveRecord class, you will have to:
73
+ * extend SimpleStateMachine::ActiveRecord,
74
+ * set the initial state in after_initialize,
75
+ * turn methods into events
91
76
 
92
77
  class User < ActiveRecord::Base
93
-
78
+
94
79
  extend SimpleStateMachine::ActiveRecord
95
80
 
96
- def after_initialize
97
- self.ssm_state ||= 'pending'
98
- # if you get an ActiveRecord::MissingAttributeError
99
- # you'll probably need to do (http://bit.ly/35q23b):
100
- # write_attribute(:ssm_state, "pending") unless read_attribute(:ssm_state)
81
+ after_initialize do
82
+ self.state ||= 'pending'
101
83
  end
102
-
84
+
103
85
  def invite
104
86
  self.activation_code = Digest::SHA1.hexdigest("salt #{Time.now.to_f}")
105
- #send_activation_email
106
87
  end
107
88
  event :invite, :pending => :invited
108
-
109
- def confirm_invitation activation_code
110
- if self.activation_code != activation_code
111
- errors.add 'activation_code', 'is invalid'
112
- end
113
- end
114
- event :confirm_invitation, :invited => :active
115
89
  end
116
90
 
117
- This generates the following event methods
118
- - invite!
119
- - confirm_invitation!
91
+ user = User.new
92
+ user.pending? # => true
93
+ user.invite # => true
94
+ user.invited? # => true
95
+ user.activation_code # => 'SOMEDIGEST'
120
96
 
121
- And the following methods to query the state:
122
- - pending?
123
- - invited?
124
- - active?
97
+ For the invite method this generates the following event methods
98
+ * *invite* (behaves like ActiveRecord save )
99
+ * *invite!* (behaves like ActiveRecord save!)
125
100
 
126
101
  If you want to be more verbose you can also use:
127
- - invite_and_save (behave like ActiveRecord save)
128
- - invite_and_save! (is equal to invite! and behaves like save!)
102
+ * *invite_and_save* (alias for invite)
103
+ * *invite_and_save!* (alias for invite!)
129
104
 
130
- == Mountable Example
131
105
 
132
- You can define your state machine in a seperate class:
106
+ === Using ActiveRecord / ActiveModel validations
107
+
108
+ When using ActiveRecord / ActiveModel you can add an error to the errors object.
109
+ This will prevent the state from being changed.
110
+
111
+ If we add an activate_account method to User
133
112
 
134
- class MyStateMachine < SimpleStateMachine::StateMachineDefinition
135
- def initialize(subject)
136
- self.lazy_decorator = lambda { SimpleStateMachine::Decorator.new(subject) }
137
- add_transition(:invite, :new, :invited)
138
- add_transition(:confirm_invitation, :invited, :active)
113
+ class User < ActiveRecord::Base
114
+ ...
115
+ def activate_account(activation_code)
116
+ if activation_code_invalid?(activation_code)
117
+ errors.add(:activation_code, 'Invalid')
118
+ end
139
119
  end
120
+ event :activate_account, :invited => :confirmed
121
+ ...
140
122
  end
141
123
 
142
- class User < ActiveRecord::Base
143
-
144
- extend SimpleStateMachine::Mountable
145
- self.state_machine_definition = MyStateMachine.new self
124
+ user.confirm_invitation!('INVALID') # => raises ActiveRecord::RecordInvalid,
125
+ # "Validation failed: Activation code is invalid"
126
+ user.confirmed? # => false
127
+ user.confirm_invitation!('VALID')
128
+ user.confirmed? # => true
146
129
 
147
- def after_initialize
148
- self.ssm_state ||= 'new'
149
- end
150
-
130
+ == Mountable StateMachines
131
+
132
+ If you like to separate your state machine from your model class, you can do so as following:
133
+
134
+ class MyStateMachine < SimpleStateMachine::StateMachineDefinition
135
+
136
+ event :invite, :new => :invited
137
+ event :confirm_invitation, :invited => :active
138
+
139
+ def decorator_class
140
+ SimpleStateMachine::Decorator::Default
141
+ end
142
+ end
143
+
144
+ class User < ActiveRecord::Base
145
+
146
+ extend SimpleStateMachine::Mountable
147
+ mount_state_machine MyStateMachine
148
+
149
+ after_initialize do
150
+ self.state ||= 'new'
151
151
  end
152
152
 
153
+ end
154
+
153
155
 
154
- == Generating google chart visualizations
156
+ == Transitions
155
157
 
156
- If your using rails you get rake tasks for generating a graphiz google chart of the state machine.
158
+ === Catching all from states
159
+ If an event should transition from all other defined states, you can use the *:all* state:
160
+
161
+ event :suspend, :all => :suspended
162
+
163
+
164
+ === Catching exceptions
165
+
166
+ You can let the state machine handle exceptions by specifying the failure state for an Error:
167
+
168
+ def download_data
169
+ raise Service::ConnectionError, "Uhoh"
170
+ end
171
+ event :download_data, Service::ConnectionError => :download_failed
157
172
 
173
+ download_data # catches Service::ConnectionError
174
+ state # => "download_failed"
175
+ state_machine.raised_error # "Uhoh"
176
+
177
+
178
+ === Default error state
179
+
180
+ To automatically catch all exceptions to a default error state use default_error_state:
181
+
182
+ state_machine_definition.default_error_state = :failed
183
+
184
+ == Transactions
185
+
186
+ If you want to run events in transactions run them in a transaction block:
187
+
188
+ user.transaction { user.invite! }
189
+
190
+ == Tools
191
+
192
+ ===Generating state diagrams
193
+
194
+ When using Rails/ActiveRecord you can generate a state diagram of the state machine via the
195
+ built in rake tasks.
196
+ For details run:
197
+
198
+ rake -T ssm
199
+
200
+ A Googlechart example:
201
+ http://tinyurl.com/79xztr6
202
+
203
+ == Installation
204
+
205
+ Use gem install:
206
+
207
+ gem install simple_state_machine
208
+
209
+ Or add it to your Gemfile:
210
+
211
+ gem 'simple_state_machine'
158
212
 
159
213
  == Note on Patches/Pull Requests
160
-
214
+
161
215
  * Fork the project.
162
216
  * Make your feature addition or bug fix.
163
217
  * Add tests for it. This is important so I don't break it in a
@@ -166,6 +220,7 @@ If your using rails you get rake tasks for generating a graphiz google chart of
166
220
  (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
167
221
  * Send me a pull request. Bonus points for topic branches.
168
222
 
223
+
169
224
  == Copyright
170
225
 
171
226
  Copyright (c) 2010 Marek & Petrik. See LICENSE for details.
@@ -2,19 +2,19 @@
2
2
  #
3
3
  # class Conversation
4
4
  # include AASM
5
- #
5
+ #
6
6
  # aasm_column :current_state # defaults to aasm_state
7
- #
7
+ #
8
8
  # aasm_initial_state :unread
9
- #
9
+ #
10
10
  # aasm_state :unread
11
11
  # aasm_state :read
12
12
  # aasm_state :closed
13
- #
13
+ #
14
14
  # aasm_event :view do
15
15
  # transitions :to => :read, :from => [:unread]
16
16
  # end
17
- #
17
+ #
18
18
  # aasm_event :close do
19
19
  # transitions :to => :closed, :from => [:read, :unread]
20
20
  # end
data/examples/lamp.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  class Lamp
2
-
2
+
3
3
  extend SimpleStateMachine
4
4
 
5
5
  def initialize
6
6
  self.state = 'off'
7
7
  end
8
-
8
+
9
9
  def push_button1
10
10
  puts "click1: #{state}"
11
11
  end
12
- event :push_button1, :off => :on,
12
+ event :push_button1, :off => :on,
13
13
  :on => :off
14
-
14
+
15
15
  def push_button2
16
16
  puts "click2: #{state}"
17
17
  end
18
18
  event :push_button2, :off => :on,
19
19
  :on => :off
20
20
 
21
- end
21
+ end
@@ -2,23 +2,23 @@
2
2
  #
3
3
  # class Relationship
4
4
  # include AASM
5
- #
5
+ #
6
6
  # aasm_column :status
7
- #
7
+ #
8
8
  # aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }
9
- #
9
+ #
10
10
  # aasm_state :dating, :enter => :make_happy, :exit => :make_depressed
11
11
  # aasm_state :intimate, :enter => :make_very_happy, :exit => :never_speak_again
12
12
  # aasm_state :married, :enter => :give_up_intimacy, :exit => :buy_exotic_car_and_wear_a_combover
13
- #
13
+ #
14
14
  # aasm_event :get_intimate do
15
15
  # transitions :to => :intimate, :from => [:dating], :guard => :drunk?
16
16
  # end
17
- #
17
+ #
18
18
  # aasm_event :get_married do
19
19
  # transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood?
20
20
  # end
21
- #
21
+ #
22
22
  # def strictly_for_fun?; end
23
23
  # def drunk?; end
24
24
  # def willing_to_give_up_manhood?; end
@@ -32,7 +32,7 @@
32
32
 
33
33
  class Relationship
34
34
  extend SimpleStateMachine
35
-
35
+
36
36
  def initialize
37
37
  self.state = relationship.strictly_for_fun? ? get_intimate : start_dating
38
38
  end
@@ -84,4 +84,4 @@ class Relationship
84
84
  def never_speak_again; end
85
85
  def give_up_intimacy; end
86
86
  def buy_exotic_car_and_wear_a_combover; end
87
- end
87
+ end
@@ -1,7 +1,7 @@
1
1
  class TrafficLight
2
-
2
+
3
3
  extend SimpleStateMachine
4
-
4
+
5
5
  def initialize
6
6
  self.state = 'green'
7
7
  end
@@ -14,4 +14,4 @@ class TrafficLight
14
14
  event :change_state, :green => :orange,
15
15
  :orange => :red,
16
16
  :red => :green
17
- end
17
+ end
data/examples/user.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  require 'digest/sha1'
2
2
  class User < ActiveRecord::Base
3
-
3
+
4
4
  validates_presence_of :name
5
-
5
+
6
6
  extend SimpleStateMachine::ActiveRecord
7
7
 
8
+ after_initialize :after_initialize
8
9
  def after_initialize
9
10
  self.state ||= 'new'
11
+ # if you get an ActiveRecord::MissingAttributeError
12
+ # you'll probably need to do (http://bit.ly/35q23b):
13
+ # write_attribute(:ssm_state, "pending") unless read_attribute(:ssm_state)
10
14
  end
11
15
 
12
16
  def invite
@@ -23,13 +27,13 @@ class User < ActiveRecord::Base
23
27
  event :confirm_invitation, :invited => :active
24
28
 
25
29
  #event :log_send_activation_code_failed, :new => :send_activation_code_failed
26
- #
30
+ #
27
31
  # def reset_password(new_password)
28
32
  # self.password = new_password
29
33
  # end
30
34
  # # do not change state, but ensure that we are in proper state
31
35
  # event :reset_password, :active => :active
32
-
36
+
33
37
  def send_activation_email(code)
34
38
  true
35
39
  end
@@ -0,0 +1,9 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ group :test do
5
+ gem "rspec"
6
+ gem "activerecord", "~>5.2.0"
7
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
8
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
9
+ end
@@ -0,0 +1,9 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ group :test do
5
+ gem "rspec"
6
+ gem "activerecord", "~>6.0.0"
7
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
8
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
9
+ end
@@ -0,0 +1,8 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ group :test do
5
+ gem "rspec"
6
+ gem "activerecord", "~>6.1.0"
7
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
8
+ end
@@ -0,0 +1,9 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ group :test do
5
+ gem "rspec"
6
+ gem "activerecord", git: "https://github.com/rails/rails.git", branch: "main"
7
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
8
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
9
+ end
@@ -0,0 +1,6 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ group :test do
5
+ gem "rspec"
6
+ end
Binary file