simple_state_machine 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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