active_recall 1.8.5 → 2.0.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +2 -2
- data/.gitignore +1 -0
- data/.tool-versions +1 -1
- data/Gemfile.lock +3 -3
- data/README.md +13 -2
- data/active_recall.gemspec +3 -3
- data/lib/active_recall/algorithms/fibonacci_sequence.rb +9 -0
- data/lib/active_recall/algorithms/leitner_system.rb +10 -1
- data/lib/active_recall/algorithms/sm2.rb +97 -0
- data/lib/active_recall/algorithms/soft_leitner_system.rb +74 -0
- data/lib/active_recall/item_methods.rb +4 -0
- data/lib/active_recall/models/item.rb +23 -3
- data/lib/active_recall/version.rb +1 -1
- data/lib/active_recall.rb +4 -0
- data/lib/generators/active_recall/active_recall_generator.rb +1 -0
- data/lib/generators/active_recall/templates/add_active_recall_item_easiness_factor.rb +11 -0
- metadata +15 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5241d31af65cc21d9fd3ab8a68696587e5af6fdfe62ecf6b4ab719eadda9ee80
|
4
|
+
data.tar.gz: 7572b3444399f07faa04c093ca4b0f0b95f0d272804aee5e884852824f5718c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d44c8efe2acb539484adcb6c4d421ddebf2cdfb35b05c9b49e02c72a65ea1047c8b7dd145261fbbd9e8678221dc5300cdc3551600e263ac7b52947a78d94660
|
7
|
+
data.tar.gz: bb043b33bd7242b2020a65d4e9e10953dcfbd136e42c5ac0964110c01a26400ad3b0a655d23ca2d74e634d7d41c8791d504f2cca78007c9db0cf49b35dd790c2
|
data/.github/workflows/tests.yml
CHANGED
@@ -19,16 +19,16 @@ jobs:
|
|
19
19
|
- macos
|
20
20
|
- ubuntu
|
21
21
|
ruby:
|
22
|
-
- 2.7
|
23
22
|
- 3.0
|
24
23
|
- 3.1
|
25
24
|
- 3.2
|
25
|
+
- 3.3
|
26
26
|
allow_failures:
|
27
27
|
- false
|
28
28
|
include:
|
29
29
|
- os: ubuntu
|
30
30
|
ruby: ruby-head
|
31
|
-
allow_failures:
|
31
|
+
allow_failures: true
|
32
32
|
env:
|
33
33
|
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
|
34
34
|
ALLOW_FAILURES: "${{ matrix.allow_failures }}"
|
data/.gitignore
CHANGED
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 3.
|
1
|
+
ruby 3.3.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
**ActiveRecall** is a spaced-repetition system that allows you to treat arbitrary [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord) models as if they were flashcards to be learned and reviewed.
|
4
4
|
It it based on, and is intended to be backwards compatible with, the [okubo](https://github.com/rgravina/okubo) gem.
|
5
|
-
The primary differentiating features are that it lets the user specify the scheduling algorithm and is fully compatible with Rails 6+ and Ruby 3+.
|
5
|
+
The primary differentiating features are that it lets the user specify the scheduling algorithm and is fully compatible with (and requires) Rails 6+ and Ruby 3+.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -35,6 +35,7 @@ ActiveRecall.configure do |config|
|
|
35
35
|
config.algorithm_class = ActiveRecall::FibonacciSequence
|
36
36
|
end
|
37
37
|
```
|
38
|
+
Algorithms include `FibonacciSequence`, `LeitnerSystem`, `SoftLeitnerSystem`, and `SM2` (see [here](https://en.wikipedia.org/wiki/SuperMemo#Description_of_SM-2_algorithm)).
|
38
39
|
For Rails applications, try doing this from within an [initializer file](https://guides.rubyonrails.org/configuring.html#using-initializer-files).
|
39
40
|
|
40
41
|
Assume you have an application allowing your users to study words in a foreign language. Using the `has_deck` method you can set up a deck of flashcards that the user will study:
|
@@ -58,7 +59,7 @@ You can add words and record attempts to guess the word as right or wrong. Vario
|
|
58
59
|
user.words << word
|
59
60
|
user.words.untested #=> [word]
|
60
61
|
|
61
|
-
# Guessing a word correctly
|
62
|
+
# Guessing a word correctly (when using a binary algorithm)
|
62
63
|
user.right_answer_for!(word)
|
63
64
|
user.words.known #=> [word]
|
64
65
|
|
@@ -92,6 +93,16 @@ user.right_answer_for!(word)
|
|
92
93
|
user.words.expired #=> [word]
|
93
94
|
```
|
94
95
|
|
96
|
+
When using a gradable algorithm (rather than binary) such as the SM2 algorithm, you will need to supply your own grade along with the item:
|
97
|
+
```ruby
|
98
|
+
grade = 3
|
99
|
+
user.score!(grade, word)
|
100
|
+
|
101
|
+
# Using the binary-only methods will raise an error
|
102
|
+
user.right_answer_for!(word)
|
103
|
+
=> ActiveRecall::IncompatibleAlgorithmError
|
104
|
+
```
|
105
|
+
|
95
106
|
Reviewing
|
96
107
|
---------
|
97
108
|
|
data/active_recall.gemspec
CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency "rdoc"
|
37
37
|
spec.add_development_dependency "rspec", ">= 3.0"
|
38
38
|
spec.add_development_dependency "sqlite3"
|
39
|
-
spec.add_runtime_dependency "activerecord", ">=
|
40
|
-
spec.add_runtime_dependency "activesupport", ">=
|
41
|
-
spec.required_ruby_version = ">=
|
39
|
+
spec.add_runtime_dependency "activerecord", ">= 6.0", "<= 7.2"
|
40
|
+
spec.add_runtime_dependency "activesupport", ">= 6.0", "<= 7.2"
|
41
|
+
spec.required_ruby_version = ">= 3.0"
|
42
42
|
end
|
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module ActiveRecall
|
4
4
|
class FibonacciSequence
|
5
|
+
def self.required_attributes
|
6
|
+
REQUIRED_ATTRIBUTES
|
7
|
+
end
|
8
|
+
|
5
9
|
def self.right(box:, times_right:, times_wrong:, current_time: Time.current)
|
6
10
|
new(
|
7
11
|
box: box,
|
@@ -11,6 +15,10 @@ module ActiveRecall
|
|
11
15
|
).right
|
12
16
|
end
|
13
17
|
|
18
|
+
def self.type
|
19
|
+
:binary
|
20
|
+
end
|
21
|
+
|
14
22
|
def self.wrong(box:, times_right:, times_wrong:, current_time: Time.current)
|
15
23
|
new(
|
16
24
|
box: box,
|
@@ -51,6 +59,7 @@ module ActiveRecall
|
|
51
59
|
|
52
60
|
attr_reader :box, :current_time, :times_right, :times_wrong
|
53
61
|
|
62
|
+
REQUIRED_ATTRIBUTES = [:box, :times_right, :times_wrong].freeze
|
54
63
|
SEQUENCE = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765].freeze
|
55
64
|
|
56
65
|
def fibonacci_number_at(index)
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module ActiveRecall
|
4
4
|
class LeitnerSystem
|
5
|
-
|
5
|
+
def self.required_attributes
|
6
|
+
REQUIRED_ATTRIBUTES
|
7
|
+
end
|
6
8
|
|
7
9
|
def self.right(box:, times_right:, times_wrong:, current_time: Time.current)
|
8
10
|
new(
|
@@ -13,6 +15,10 @@ module ActiveRecall
|
|
13
15
|
).right
|
14
16
|
end
|
15
17
|
|
18
|
+
def self.type
|
19
|
+
:binary
|
20
|
+
end
|
21
|
+
|
16
22
|
def self.wrong(box:, times_right:, times_wrong:, current_time: Time.current)
|
17
23
|
new(
|
18
24
|
box: box,
|
@@ -53,6 +59,9 @@ module ActiveRecall
|
|
53
59
|
|
54
60
|
attr_reader :box, :current_time, :times_right, :times_wrong
|
55
61
|
|
62
|
+
DELAYS = [3, 7, 14, 30, 60, 120, 240].freeze
|
63
|
+
REQUIRED_ATTRIBUTES = [:box, :times_right, :times_wrong].freeze
|
64
|
+
|
56
65
|
def next_review
|
57
66
|
(current_time + DELAYS[[DELAYS.count, box + 1].min - 1].days)
|
58
67
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecall
|
4
|
+
class SM2
|
5
|
+
MIN_EASINESS_FACTOR = 1.3
|
6
|
+
|
7
|
+
def self.required_attributes
|
8
|
+
REQUIRED_ATTRIBUTES
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.score(box:, easiness_factor:, times_right:, times_wrong:, grade:, current_time: Time.current)
|
12
|
+
new(
|
13
|
+
box: box,
|
14
|
+
easiness_factor: easiness_factor,
|
15
|
+
times_right: times_right,
|
16
|
+
times_wrong: times_wrong,
|
17
|
+
grade: grade,
|
18
|
+
current_time: current_time
|
19
|
+
).score
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.type
|
23
|
+
:gradable
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(box:, easiness_factor:, times_right:, times_wrong:, grade:, current_time: Time.current)
|
27
|
+
@box = box
|
28
|
+
@easiness_factor = easiness_factor || 2.5
|
29
|
+
@times_right = times_right
|
30
|
+
@times_wrong = times_wrong
|
31
|
+
@grade = grade
|
32
|
+
@current_time = current_time
|
33
|
+
@interval = [1, box].max
|
34
|
+
end
|
35
|
+
|
36
|
+
def score
|
37
|
+
raise "Grade must be between 0-5!" unless GRADES.include?(@grade)
|
38
|
+
update_easiness_factor
|
39
|
+
update_repetition_and_interval
|
40
|
+
|
41
|
+
{
|
42
|
+
box: @box,
|
43
|
+
easiness_factor: @easiness_factor,
|
44
|
+
times_right: @times_right,
|
45
|
+
times_wrong: @times_wrong,
|
46
|
+
last_reviewed: @current_time,
|
47
|
+
next_review: next_review
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
GRADES = [
|
54
|
+
5, # Perfect response. The learner recalls the information without hesitation.
|
55
|
+
4, # Correct response after a hesitation. The learner recalls the information but with some difficulty.
|
56
|
+
3, # Correct response recalled with serious difficulty. The learner struggles but eventually recalls the information.
|
57
|
+
2, # Incorrect response, but the learner was very close to the correct answer. This might involve recalling some of the information correctly but not all of it.
|
58
|
+
1, # Incorrect response, but the learner feels they should have remembered it. This is typically used when the learner has a sense of familiarity with the material but fails to recall it correctly.
|
59
|
+
0 # Complete blackout. The learner does not recall the information at all.
|
60
|
+
].freeze
|
61
|
+
REQUIRED_ATTRIBUTES = [
|
62
|
+
:box,
|
63
|
+
:easiness_factor,
|
64
|
+
:grade,
|
65
|
+
:times_right,
|
66
|
+
:times_wrong
|
67
|
+
].freeze
|
68
|
+
|
69
|
+
def update_easiness_factor
|
70
|
+
@easiness_factor += (0.1 - (5 - @grade) * (0.08 + (5 - @grade) * 0.02))
|
71
|
+
@easiness_factor = [@easiness_factor, MIN_EASINESS_FACTOR].max
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_repetition_and_interval
|
75
|
+
if @grade >= 3
|
76
|
+
@box += 1
|
77
|
+
@times_right += 1
|
78
|
+
@interval = case @box
|
79
|
+
when 1
|
80
|
+
1
|
81
|
+
when 2
|
82
|
+
6
|
83
|
+
else
|
84
|
+
(@interval || 1) * @easiness_factor
|
85
|
+
end
|
86
|
+
else
|
87
|
+
@box = 0
|
88
|
+
@times_wrong += 1
|
89
|
+
@interval = 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def next_review
|
94
|
+
@current_time + @interval.days
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecall
|
4
|
+
class SoftLeitnerSystem
|
5
|
+
def self.required_attributes
|
6
|
+
REQUIRED_ATTRIBUTES
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.right(box:, times_right:, times_wrong:, current_time: Time.current)
|
10
|
+
new(
|
11
|
+
box: box,
|
12
|
+
current_time: current_time,
|
13
|
+
times_right: times_right,
|
14
|
+
times_wrong: times_wrong
|
15
|
+
).right
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.type
|
19
|
+
:binary
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.wrong(box:, times_right:, times_wrong:, current_time: Time.current)
|
23
|
+
new(
|
24
|
+
box: box,
|
25
|
+
current_time: current_time,
|
26
|
+
times_right: times_right,
|
27
|
+
times_wrong: times_wrong
|
28
|
+
).wrong
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(box:, times_right:, times_wrong:, current_time: Time.current)
|
32
|
+
@box = box
|
33
|
+
@current_time = current_time
|
34
|
+
@times_right = times_right
|
35
|
+
@times_wrong = times_wrong
|
36
|
+
end
|
37
|
+
|
38
|
+
def right
|
39
|
+
self.box = [box + 1, DELAYS.count].min
|
40
|
+
|
41
|
+
{
|
42
|
+
box: box,
|
43
|
+
times_right: times_right + 1,
|
44
|
+
times_wrong: times_wrong,
|
45
|
+
last_reviewed: current_time,
|
46
|
+
next_review: next_review
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def wrong
|
51
|
+
self.box = [box - 1, 0].max
|
52
|
+
|
53
|
+
{
|
54
|
+
box: box,
|
55
|
+
times_right: times_right,
|
56
|
+
times_wrong: times_wrong + 1,
|
57
|
+
last_reviewed: current_time,
|
58
|
+
next_review: next_review
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
DELAYS = [3, 7, 14, 30, 60, 120, 240].freeze
|
65
|
+
REQUIRED_ATTRIBUTES = [:box, :times_right, :times_wrong].freeze
|
66
|
+
|
67
|
+
attr_accessor :box
|
68
|
+
attr_reader :current_time, :times_right, :times_wrong
|
69
|
+
|
70
|
+
def next_review
|
71
|
+
(current_time + DELAYS[[DELAYS.count, box].min - 1].days)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -17,16 +17,34 @@ module ActiveRecall
|
|
17
17
|
where(["box > ? and next_review > ?", 0, current_time])
|
18
18
|
end
|
19
19
|
|
20
|
+
def score!(grade)
|
21
|
+
if algorithm_class.type == :gradable
|
22
|
+
update!(
|
23
|
+
algorithm_class.score(**scoring_attributes.merge(grade: grade))
|
24
|
+
).score
|
25
|
+
else
|
26
|
+
raise IncompatibleAlgorithmError, "#{algorithm_class.name} is a not an gradable algorithm, so is not compatible with the #score! method"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
def source
|
21
31
|
source_type.constantize.find(source_id)
|
22
32
|
end
|
23
33
|
|
24
34
|
def right!
|
25
|
-
|
35
|
+
if algorithm_class.type == :binary
|
36
|
+
update!(algorithm_class.right(**scoring_attributes))
|
37
|
+
else
|
38
|
+
raise IncompatibleAlgorithmError, "#{algorithm_class.name} is not a binary algorithm, so is not compatible with the #right! method"
|
39
|
+
end
|
26
40
|
end
|
27
41
|
|
28
42
|
def wrong!
|
29
|
-
|
43
|
+
if algorithm_class.type == :binary
|
44
|
+
update!(algorithm_class.wrong(**scoring_attributes))
|
45
|
+
else
|
46
|
+
raise IncompatibleAlgorithmError, "#{algorithm_class.name} is not a binary algorithm, so is not compatible with the #wrong! method"
|
47
|
+
end
|
30
48
|
end
|
31
49
|
|
32
50
|
private
|
@@ -36,7 +54,9 @@ module ActiveRecall
|
|
36
54
|
end
|
37
55
|
|
38
56
|
def scoring_attributes
|
39
|
-
attributes
|
57
|
+
attributes
|
58
|
+
.symbolize_keys
|
59
|
+
.slice(*algorithm_class.required_attributes)
|
40
60
|
end
|
41
61
|
end
|
42
62
|
end
|
data/lib/active_recall.rb
CHANGED
@@ -5,6 +5,8 @@ require "active_recall/deck_methods"
|
|
5
5
|
require "active_recall/item_methods"
|
6
6
|
require "active_recall/algorithms/fibonacci_sequence"
|
7
7
|
require "active_recall/algorithms/leitner_system"
|
8
|
+
require "active_recall/algorithms/soft_leitner_system"
|
9
|
+
require "active_recall/algorithms/sm2"
|
8
10
|
require "active_recall/configuration"
|
9
11
|
require "active_recall/models/deck"
|
10
12
|
require "active_recall/models/item"
|
@@ -28,4 +30,6 @@ module ActiveRecall
|
|
28
30
|
def self.reset
|
29
31
|
@configuration = Configuration.new
|
30
32
|
end
|
33
|
+
|
34
|
+
class IncompatibleAlgorithmError < StandardError; end
|
31
35
|
end
|
@@ -20,6 +20,7 @@ class ActiveRecallGenerator < Rails::Generators::Base
|
|
20
20
|
def create_migration_files
|
21
21
|
create_migration_file_if_not_exist "create_active_recall_tables"
|
22
22
|
create_migration_file_if_not_exist "add_active_recall_item_answer_counts"
|
23
|
+
create_migration_file_if_not_exist "add_active_recall_item_easiness_factor"
|
23
24
|
create_migration_file_if_not_exist "migrate_okubo_to_active_recall" if options["migrate_data"]
|
24
25
|
end
|
25
26
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddActiveRecallItemEasinessFactor < ActiveRecord::Migration[5.2]
|
4
|
+
def self.up
|
5
|
+
add_column :active_recall_items, :easiness_factor, :float, default: 2.5
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
remove_column :active_recall_items, :easiness_factor
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_recall
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Gravina
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-01-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -73,40 +73,40 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
76
|
+
version: '6.0'
|
77
77
|
- - "<="
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: '7.
|
79
|
+
version: '7.2'
|
80
80
|
type: :runtime
|
81
81
|
prerelease: false
|
82
82
|
version_requirements: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
86
|
+
version: '6.0'
|
87
87
|
- - "<="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '7.
|
89
|
+
version: '7.2'
|
90
90
|
- !ruby/object:Gem::Dependency
|
91
91
|
name: activesupport
|
92
92
|
requirement: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: '6.0'
|
97
97
|
- - "<="
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: '7.
|
99
|
+
version: '7.2'
|
100
100
|
type: :runtime
|
101
101
|
prerelease: false
|
102
102
|
version_requirements: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
104
|
- - ">="
|
105
105
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
106
|
+
version: '6.0'
|
107
107
|
- - "<="
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '7.
|
109
|
+
version: '7.2'
|
110
110
|
description: A spaced-repetition system to be used with ActiveRecord models
|
111
111
|
email:
|
112
112
|
- robert.gravina@gmail.com
|
@@ -130,6 +130,8 @@ files:
|
|
130
130
|
- lib/active_recall.rb
|
131
131
|
- lib/active_recall/algorithms/fibonacci_sequence.rb
|
132
132
|
- lib/active_recall/algorithms/leitner_system.rb
|
133
|
+
- lib/active_recall/algorithms/sm2.rb
|
134
|
+
- lib/active_recall/algorithms/soft_leitner_system.rb
|
133
135
|
- lib/active_recall/base.rb
|
134
136
|
- lib/active_recall/configuration.rb
|
135
137
|
- lib/active_recall/deck_methods.rb
|
@@ -139,6 +141,7 @@ files:
|
|
139
141
|
- lib/active_recall/version.rb
|
140
142
|
- lib/generators/active_recall/active_recall_generator.rb
|
141
143
|
- lib/generators/active_recall/templates/add_active_recall_item_answer_counts.rb
|
144
|
+
- lib/generators/active_recall/templates/add_active_recall_item_easiness_factor.rb
|
142
145
|
- lib/generators/active_recall/templates/create_active_recall_tables.rb
|
143
146
|
- lib/generators/active_recall/templates/migrate_okubo_to_active_recall.rb
|
144
147
|
homepage: https://github.com/jaysonvirissimo/active_recall
|
@@ -154,14 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
157
|
requirements:
|
155
158
|
- - ">="
|
156
159
|
- !ruby/object:Gem::Version
|
157
|
-
version: '
|
160
|
+
version: '3.0'
|
158
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
162
|
requirements:
|
160
163
|
- - ">="
|
161
164
|
- !ruby/object:Gem::Version
|
162
165
|
version: '0'
|
163
166
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
167
|
+
rubygems_version: 3.5.3
|
165
168
|
signing_key:
|
166
169
|
specification_version: 4
|
167
170
|
summary: A spaced-repetition system
|