mini_kraken 0.2.00 → 0.2.01
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/.rubocop.yml +334 -0
- data/CHANGELOG.md +9 -0
- data/README.md +13 -11
- data/lib/mini_kraken/core/atomic_term.rb +1 -0
- data/lib/mini_kraken/core/cons_cell.rb +1 -0
- data/lib/mini_kraken/core/def_relation.rb +1 -0
- data/lib/mini_kraken/core/environment.rb +1 -1
- data/lib/mini_kraken/core/equals.rb +2 -5
- data/lib/mini_kraken/core/formal_ref.rb +1 -0
- data/lib/mini_kraken/core/goal.rb +3 -2
- data/lib/mini_kraken/core/goal_template.rb +3 -1
- data/lib/mini_kraken/core/k_symbol.rb +1 -1
- data/lib/mini_kraken/core/variable_ref.rb +1 -0
- data/lib/mini_kraken/glue/dsl.rb +115 -9
- data/lib/mini_kraken/glue/run_star_expression.rb +1 -3
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +6 -3
- data/spec/.rubocop.yml +13 -0
- data/spec/core/duck_fiber_spec.rb +1 -1
- data/spec/core/k_symbol_spec.rb +1 -1
- data/spec/glue/dsl_chap1_spec.rb +133 -37
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f51855ac3179a111a4ace328340402fa167818773086076abf90ed845c31d248
|
4
|
+
data.tar.gz: f6bde0d3d7b872461d7cb0b087eaab821240f14317445e95f4d832d09af51e2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae6319164a2f6212bdbdea35dd5b5befa86648b685063dea79d220b70e5852c3e8b343d2d37ebfe6584aa3966b44174e91df2866d63e03a219a0008a5b382d66
|
7
|
+
data.tar.gz: 70eb204ab842ea45527bd5ca8661dcd98081422cae4d6848d220bc70e080da94b3b7078f3602f1143535821a9894309b9bec39ec5f4d6c60edcfd21cfa5c8f4f
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,334 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'exp/**/*'
|
4
|
+
|
5
|
+
Layout/ArgumentAlignment:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Layout/ArrayAlignment:
|
9
|
+
Enabled: true
|
10
|
+
EnforcedStyle: with_fixed_indentation
|
11
|
+
|
12
|
+
Layout/CaseIndentation:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Layout/ClosingHeredocIndentation:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Layout/CommentIndentation:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Layout/ElseAlignment:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Layout/EmptyLines:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Layout/EndAlignment:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Layout/EndOfLine:
|
31
|
+
Enabled: true
|
32
|
+
EnforcedStyle: lf
|
33
|
+
|
34
|
+
Layout/FirstArgumentIndentation:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Layout/IndentationWidth:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Layout/IndentationConsistency:
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
Layout/HeredocIndentation:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Layout/MultilineHashBraceLayout:
|
47
|
+
Enabled: true
|
48
|
+
|
49
|
+
Layout/MultilineMethodCallBraceLayout:
|
50
|
+
Enabled: true
|
51
|
+
EnforcedStyle: same_line
|
52
|
+
|
53
|
+
Layout/SpaceAroundOperators:
|
54
|
+
Enabled: true
|
55
|
+
|
56
|
+
Layout/SpaceInsideParens:
|
57
|
+
Enabled: true
|
58
|
+
|
59
|
+
Layout/IndentationStyle:
|
60
|
+
Enabled: true
|
61
|
+
|
62
|
+
Layout/SpaceAroundMethodCallOperator:
|
63
|
+
Enabled: true
|
64
|
+
|
65
|
+
Layout/TrailingEmptyLines:
|
66
|
+
Enabled: true
|
67
|
+
|
68
|
+
Layout/TrailingWhitespace:
|
69
|
+
Enabled: true
|
70
|
+
|
71
|
+
Lint/Loop:
|
72
|
+
Enabled: true
|
73
|
+
|
74
|
+
Lint/RaiseException:
|
75
|
+
Enabled: true
|
76
|
+
|
77
|
+
Lint/RescueException:
|
78
|
+
Enabled: true
|
79
|
+
|
80
|
+
Lint/StructNewOverride:
|
81
|
+
Enabled: true
|
82
|
+
|
83
|
+
Lint/UnusedMethodArgument:
|
84
|
+
Enabled: true
|
85
|
+
|
86
|
+
Lint/UselessAccessModifier:
|
87
|
+
Enabled: true
|
88
|
+
|
89
|
+
Lint/Void:
|
90
|
+
Enabled: false
|
91
|
+
|
92
|
+
Lint/UselessAssignment:
|
93
|
+
Enabled: true
|
94
|
+
|
95
|
+
Metrics/AbcSize:
|
96
|
+
Enabled: false
|
97
|
+
|
98
|
+
Metrics/BlockLength:
|
99
|
+
Enabled: true
|
100
|
+
Max: 350
|
101
|
+
|
102
|
+
Metrics/BlockNesting:
|
103
|
+
Enabled: true
|
104
|
+
Max: 5
|
105
|
+
|
106
|
+
Metrics/ClassLength:
|
107
|
+
Enabled: true
|
108
|
+
Max: 350
|
109
|
+
|
110
|
+
Metrics/CyclomaticComplexity:
|
111
|
+
Enabled: false
|
112
|
+
|
113
|
+
Layout/LineLength:
|
114
|
+
Enabled: false
|
115
|
+
Max: 90
|
116
|
+
|
117
|
+
Metrics/MethodLength:
|
118
|
+
Enabled: true
|
119
|
+
Max: 50
|
120
|
+
|
121
|
+
Metrics/ModuleLength:
|
122
|
+
Enabled: true
|
123
|
+
Max: 500
|
124
|
+
|
125
|
+
Metrics/PerceivedComplexity:
|
126
|
+
Enabled: false
|
127
|
+
|
128
|
+
Naming/ConstantName:
|
129
|
+
Enabled: false
|
130
|
+
|
131
|
+
Naming/ClassAndModuleCamelCase:
|
132
|
+
Enabled: false
|
133
|
+
|
134
|
+
Naming/BlockParameterName:
|
135
|
+
Enabled: true
|
136
|
+
|
137
|
+
Naming/MethodParameterName:
|
138
|
+
Enabled: false
|
139
|
+
|
140
|
+
Naming/VariableName:
|
141
|
+
Enabled: false
|
142
|
+
|
143
|
+
Style/Alias:
|
144
|
+
Enabled: true
|
145
|
+
|
146
|
+
Layout/HashAlignment:
|
147
|
+
Enabled: false
|
148
|
+
|
149
|
+
Style/AsciiComments:
|
150
|
+
Enabled: false
|
151
|
+
|
152
|
+
Style/BarePercentLiterals:
|
153
|
+
Enabled: false
|
154
|
+
|
155
|
+
Style/BlockComments:
|
156
|
+
Enabled: false
|
157
|
+
|
158
|
+
Style/CharacterLiteral:
|
159
|
+
Enabled: false
|
160
|
+
|
161
|
+
Style/ClassCheck:
|
162
|
+
Enabled: false
|
163
|
+
|
164
|
+
Style/ClassVars:
|
165
|
+
Enabled: false
|
166
|
+
|
167
|
+
Style/ColonMethodCall:
|
168
|
+
Enabled: false
|
169
|
+
|
170
|
+
Style/CommentAnnotation:
|
171
|
+
Enabled: false
|
172
|
+
|
173
|
+
Style/CommentedKeyword:
|
174
|
+
Enabled: false
|
175
|
+
|
176
|
+
Style/ConditionalAssignment:
|
177
|
+
Enabled: false
|
178
|
+
|
179
|
+
Style/DefWithParentheses:
|
180
|
+
Enabled: true
|
181
|
+
|
182
|
+
Style/Documentation:
|
183
|
+
Enabled: false
|
184
|
+
|
185
|
+
Style/ExpandPathArguments:
|
186
|
+
Enabled: false
|
187
|
+
|
188
|
+
Style/ExponentialNotation:
|
189
|
+
Enabled: true
|
190
|
+
|
191
|
+
Style/GuardClause:
|
192
|
+
Enabled: false
|
193
|
+
|
194
|
+
Style/HashEachMethods:
|
195
|
+
Enabled: true
|
196
|
+
|
197
|
+
Style/HashTransformKeys:
|
198
|
+
Enabled: true
|
199
|
+
|
200
|
+
Style/HashTransformValues:
|
201
|
+
Enabled: true
|
202
|
+
|
203
|
+
Style/IfUnlessModifier:
|
204
|
+
Enabled: false
|
205
|
+
|
206
|
+
Style/InverseMethods:
|
207
|
+
Enabled: true
|
208
|
+
|
209
|
+
Style/MissingRespondToMissing:
|
210
|
+
Enabled: false
|
211
|
+
|
212
|
+
Style/Next:
|
213
|
+
Enabled: false
|
214
|
+
|
215
|
+
Style/NumericLiterals:
|
216
|
+
Enabled: false
|
217
|
+
|
218
|
+
Style/RaiseArgs:
|
219
|
+
Enabled: true
|
220
|
+
|
221
|
+
Style/RedundantReturn:
|
222
|
+
Enabled: false
|
223
|
+
|
224
|
+
Style/RedundantSelf:
|
225
|
+
Enabled: true
|
226
|
+
|
227
|
+
Style/RegexpLiteral:
|
228
|
+
Enabled: false
|
229
|
+
|
230
|
+
Style/PercentLiteralDelimiters:
|
231
|
+
Enabled: false
|
232
|
+
|
233
|
+
Style/StderrPuts:
|
234
|
+
Enabled: false
|
235
|
+
|
236
|
+
Style/StringLiterals:
|
237
|
+
Enabled: true
|
238
|
+
|
239
|
+
Style/TernaryParentheses:
|
240
|
+
Enabled: false
|
241
|
+
|
242
|
+
Style/UnlessElse:
|
243
|
+
Enabled: false
|
244
|
+
|
245
|
+
# Rubocop complains when it doesn't find an explicit setting for the following cops:
|
246
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
247
|
+
Enabled: true
|
248
|
+
|
249
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
250
|
+
Enabled: true
|
251
|
+
|
252
|
+
Lint/DeprecatedOpenSSLConstant:
|
253
|
+
Enabled: true
|
254
|
+
|
255
|
+
Lint/DuplicateElsifCondition:
|
256
|
+
Enabled: true
|
257
|
+
|
258
|
+
Lint/DuplicateRescueException:
|
259
|
+
Enabled: true
|
260
|
+
|
261
|
+
Lint/EmptyConditionalBody:
|
262
|
+
Enabled: true
|
263
|
+
|
264
|
+
Lint/FloatComparison:
|
265
|
+
Enabled: true
|
266
|
+
|
267
|
+
Lint/MissingSuper:
|
268
|
+
Enabled: true
|
269
|
+
|
270
|
+
Lint/MixedRegexpCaptureTypes:
|
271
|
+
Enabled: true
|
272
|
+
|
273
|
+
Lint/OutOfRangeRegexpRef:
|
274
|
+
Enabled: true
|
275
|
+
|
276
|
+
Lint/SelfAssignment:
|
277
|
+
Enabled: true
|
278
|
+
|
279
|
+
Lint/TopLevelReturnWithArgument:
|
280
|
+
Enabled: true
|
281
|
+
|
282
|
+
Lint/UnreachableLoop:
|
283
|
+
Enabled: true
|
284
|
+
|
285
|
+
Style/AccessorGrouping:
|
286
|
+
Enabled: true
|
287
|
+
|
288
|
+
Style/ArrayCoercion:
|
289
|
+
Enabled: true
|
290
|
+
|
291
|
+
Style/BisectedAttrAccessor:
|
292
|
+
Enabled: true
|
293
|
+
|
294
|
+
Style/CaseLikeIf:
|
295
|
+
Enabled: true
|
296
|
+
|
297
|
+
Style/ExplicitBlockArgument:
|
298
|
+
Enabled: true
|
299
|
+
|
300
|
+
Style/GlobalStdStream:
|
301
|
+
Enabled: true
|
302
|
+
|
303
|
+
Style/HashAsLastArrayItem:
|
304
|
+
Enabled: true
|
305
|
+
|
306
|
+
Style/HashLikeCase:
|
307
|
+
Enabled: true
|
308
|
+
|
309
|
+
Style/OptionalBooleanParameter:
|
310
|
+
Enabled: true
|
311
|
+
|
312
|
+
Style/RedundantAssignment:
|
313
|
+
Enabled: true
|
314
|
+
|
315
|
+
Style/RedundantFetchBlock:
|
316
|
+
Enabled: true
|
317
|
+
|
318
|
+
Style/RedundantFileExtensionInRequire:
|
319
|
+
Enabled: true
|
320
|
+
|
321
|
+
Style/RedundantRegexpCharacterClass:
|
322
|
+
Enabled: true
|
323
|
+
|
324
|
+
Style/RedundantRegexpEscape:
|
325
|
+
Enabled: true
|
326
|
+
|
327
|
+
Style/SingleArgumentDig:
|
328
|
+
Enabled: true
|
329
|
+
|
330
|
+
Style/SlicingWithRange:
|
331
|
+
Enabled: true
|
332
|
+
|
333
|
+
Style/StringConcatenation:
|
334
|
+
Enabled: true
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.2.01] - 2020-08-07
|
2
|
+
- The DSL (Domain Specific Language) now supports `defrel` and boolean literals.
|
3
|
+
|
4
|
+
### CHANGED
|
5
|
+
- Constructor `DefRelation#initialize` now freezes any new class instance.
|
6
|
+
- Constructor `GoalTemplate#initialize` now freezes any new class instance.
|
7
|
+
- Mixin module `Core::DSL` new method `defrel` to build custom relations.
|
8
|
+
- File `.rubocop.yml` to please Rubocop 0.89
|
9
|
+
|
1
10
|
## [0.2.00] - 2020-07-12
|
2
11
|
- First release of DSL (Domain Specific Language)
|
3
12
|
- Fix defect for fused variables that remain fresh
|
data/README.md
CHANGED
@@ -30,12 +30,12 @@ ISBN: 9780262535519, (2018), MIT Press.
|
|
30
30
|
- [ ] Occurs check
|
31
31
|
|
32
32
|
List-centric relations from Chapter 2
|
33
|
-
- [ ] caro
|
34
|
-
- [ ] cdro
|
35
|
-
- [ ] conso
|
36
|
-
- [ ] nullo
|
37
|
-
- [ ] pairo
|
38
|
-
- [ ] singletono
|
33
|
+
- [ ] caro
|
34
|
+
- [ ] cdro
|
35
|
+
- [ ] conso
|
36
|
+
- [ ] nullo
|
37
|
+
- [ ] pairo
|
38
|
+
- [ ] singletono
|
39
39
|
|
40
40
|
## Installation
|
41
41
|
|
@@ -73,9 +73,9 @@ The two first lines in the above code snippet are pretty standard:
|
|
73
73
|
- The first line loads the `mini_kraken` library.
|
74
74
|
- The second line add the DSL methods to the current object.
|
75
75
|
|
76
|
-
The next line constitutes a trivial `miniKanren` program.
|
77
|
-
The aim of a `miniKanren` program is to find one or more solutions involving
|
78
|
-
and satisfying one or more goals.
|
76
|
+
The next line constitutes a trivial `miniKanren` program.
|
77
|
+
The aim of a `miniKanren` program is to find one or more solutions involving the given logical variable(s)
|
78
|
+
and satisfying one or more goals to the `run_star method.
|
79
79
|
In our example, the `run_star` method instructs `MiniKraken` to find all solutions,
|
80
80
|
knowing that each successful solution:
|
81
81
|
- binds a value to the provided variable `q` and
|
@@ -101,7 +101,8 @@ So the above program succeeds and the only found solution is obtained by binding
|
|
101
101
|
puts result # => ()
|
102
102
|
```
|
103
103
|
In this example, we learn that `run_star` can take multiple goals placed in an array.
|
104
|
-
The program fails to find a solution since it is not possible to satisfy the two `equals` goals simultaneously.
|
104
|
+
The program fails to find a solution since it is not possible to satisfy the two `equals` goals simultaneously.
|
105
|
+
In case of failure, the `run_star` returns an empty list represented as `()` in the output.
|
105
106
|
|
106
107
|
|
107
108
|
### Example 3
|
@@ -127,7 +128,8 @@ This time, `run_star` takes two logical variables -`x` and `y`- and successfully
|
|
127
128
|
puts result # => ((:blue :sea) (:blue :mountain) (:red :sea) (:red :mountain))
|
128
129
|
```
|
129
130
|
|
130
|
-
Here, `run_star` takes two logical variables and two `disj2` goals.
|
131
|
+
Here, `run_star` takes two logical variables and two `disj2` goals.
|
132
|
+
A `disj2` succeeds if any of its arguments succeeds.
|
131
133
|
This program finds four distinct solutions for x, y pairs.
|
132
134
|
|
133
135
|
## Development
|
@@ -38,10 +38,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
38
38
|
return result
|
39
39
|
end
|
40
40
|
new_arg1, new_arg2 = commute_cond(arg1, arg2, anEnv)
|
41
|
-
|
42
|
-
# anEnv.merge(result) if result.successful? && !result.association.empty?
|
43
|
-
|
44
|
-
result
|
41
|
+
do_unification(new_arg1, new_arg2, anEnv)
|
45
42
|
end
|
46
43
|
|
47
44
|
private
|
@@ -141,7 +138,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
141
138
|
total_success = subresults.all?(&:successful?)
|
142
139
|
if total_success
|
143
140
|
memo = Outcome.success(anEnv)
|
144
|
-
|
141
|
+
subresults.reduce(memo) do |sub_total, outcome|
|
145
142
|
sub_total.merge(outcome)
|
146
143
|
sub_total
|
147
144
|
end
|
@@ -16,6 +16,7 @@ module MiniKraken
|
|
16
16
|
# @param aRelation [Relation] The relation corresponding to this goal
|
17
17
|
# @param args [Array<Term>] The actual aguments of the goal
|
18
18
|
def initialize(aRelation, args)
|
19
|
+
super()
|
19
20
|
@relation = aRelation
|
20
21
|
@actuals = validated_actuals(args)
|
21
22
|
end
|
@@ -35,7 +36,7 @@ module MiniKraken
|
|
35
36
|
raise StandardError, err_msg
|
36
37
|
end
|
37
38
|
|
38
|
-
prefix =
|
39
|
+
prefix = 'Invalid goal argument'
|
39
40
|
args.each do |actual|
|
40
41
|
if actual.kind_of?(GoalArg) || actual.kind_of?(Environment)
|
41
42
|
next
|
@@ -43,7 +44,7 @@ module MiniKraken
|
|
43
44
|
validated_actuals(actual)
|
44
45
|
else
|
45
46
|
actual_display = actual.nil? ? 'nil' : actual.to_s
|
46
|
-
raise StandardError, prefix
|
47
|
+
raise StandardError, "#{prefix} '#{actual_display}'"
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
@@ -8,15 +8,17 @@ module MiniKraken
|
|
8
8
|
# The individual goals are instantiated when the formal arguments
|
9
9
|
# are bound to goal arguments
|
10
10
|
class GoalTemplate < BaseArg
|
11
|
-
# @return [Array<BaseArg>
|
11
|
+
# @return [Array<BaseArg>] Arguments of goal template.
|
12
12
|
attr_reader :args
|
13
13
|
|
14
14
|
# @return [Relation] Main relation for the goal template
|
15
15
|
attr_reader :relation
|
16
16
|
|
17
17
|
def initialize(aRelation, theArgs)
|
18
|
+
super()
|
18
19
|
@relation = validated_relation(aRelation)
|
19
20
|
@args = validated_args(theArgs)
|
21
|
+
freeze
|
20
22
|
end
|
21
23
|
|
22
24
|
# @param formals [Array<FormalArg>] Array of formal arguments
|
data/lib/mini_kraken/glue/dsl.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
3
4
|
require_relative '../core/any_value'
|
4
5
|
require_relative '../core/conj2'
|
5
6
|
require_relative '../core/cons_cell'
|
7
|
+
require_relative '../core/def_relation'
|
6
8
|
require_relative '../core/disj2'
|
7
9
|
require_relative '../core/equals'
|
8
10
|
require_relative '../core/fail'
|
11
|
+
require_relative '../core/formal_arg'
|
12
|
+
require_relative '../core/formal_ref'
|
13
|
+
require_relative '../core/goal_template'
|
14
|
+
require_relative '../core/k_boolean'
|
9
15
|
require_relative '../core/k_symbol'
|
10
16
|
require_relative '../core/succeed'
|
11
17
|
require_relative '../core/variable_ref'
|
@@ -15,31 +21,64 @@ require_relative 'run_star_expression'
|
|
15
21
|
|
16
22
|
module MiniKraken
|
17
23
|
module Glue
|
24
|
+
# The mixin module that implements the methods for the DSL
|
25
|
+
# (DSL = Domain Specific Langague) that allows MiniKraken
|
26
|
+
# users to embed Minikanren in their Ruby code.
|
18
27
|
module DSL
|
28
|
+
# A run* expression tries to find all the solutions
|
29
|
+
# that meet the given goal.
|
19
30
|
# @return [Core::ConsCell] A list of solutions
|
20
31
|
def run_star(var_names, goal)
|
21
32
|
program = RunStarExpression.new(var_names, goal)
|
22
33
|
program.run
|
23
34
|
end
|
24
35
|
|
36
|
+
# conj2 stands for conjunction of two arguments.
|
37
|
+
# Returns a goal linked to the Core::Conj2 relation.
|
38
|
+
# The rule of that relation succeeds when both arguments succeed.
|
39
|
+
# @param arg1 [Core::Goal]
|
40
|
+
# @param arg2 [Core::Goal]
|
41
|
+
# @return [Core::Failure|Core::Success]
|
25
42
|
def conj2(arg1, arg2)
|
26
|
-
|
43
|
+
goal_class.new(Core::Conj2.instance, [convert(arg1), convert(arg2)])
|
27
44
|
end
|
28
45
|
|
29
46
|
def cons(car_item, cdr_item = nil)
|
30
|
-
|
47
|
+
tail = cdr_item.nil? ? cdr_item : convert(cdr_item)
|
48
|
+
Core::ConsCell.new(convert(car_item), tail)
|
49
|
+
end
|
50
|
+
|
51
|
+
def defrel(relationName, theFormals, &aGoalTemplateExpr)
|
52
|
+
start_defrel
|
53
|
+
|
54
|
+
case theFormals
|
55
|
+
when String
|
56
|
+
@defrel_formals << theFormals
|
57
|
+
when Array
|
58
|
+
@defrel_formals.merge(theFormals)
|
59
|
+
end
|
60
|
+
|
61
|
+
formals = @defrel_formals.map { |name| Core::FormalArg.new(name) }
|
62
|
+
g_template = aGoalTemplateExpr.call
|
63
|
+
result = Core::DefRelation.new(relationName, g_template, formals)
|
64
|
+
add_defrel(result)
|
65
|
+
|
66
|
+
end_defrel
|
67
|
+
result
|
31
68
|
end
|
32
69
|
|
33
70
|
def disj2(arg1, arg2)
|
34
|
-
|
71
|
+
goal_class.new(Core::Disj2.instance, [convert(arg1), convert(arg2)])
|
35
72
|
end
|
36
73
|
|
74
|
+
# @return [Core::Fail] A goal that unconditionally fails.
|
37
75
|
def _fail
|
38
|
-
|
76
|
+
goal_class.new(Core::Fail.instance, [])
|
39
77
|
end
|
40
78
|
|
41
79
|
def equals(arg1, arg2)
|
42
|
-
|
80
|
+
# require 'debug'
|
81
|
+
goal_class.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
|
43
82
|
end
|
44
83
|
|
45
84
|
def fresh(var_names, goal)
|
@@ -47,19 +86,30 @@ module MiniKraken
|
|
47
86
|
|
48
87
|
if var_names.kind_of?(String) || var_names.kind_of?(Core::VariableRef)
|
49
88
|
vars = [var_names]
|
50
|
-
|
51
|
-
|
89
|
+
else
|
52
90
|
vars = var_names
|
53
91
|
end
|
92
|
+
|
54
93
|
FreshEnv.new(vars, goal)
|
55
94
|
end
|
56
95
|
|
96
|
+
def list(*members)
|
97
|
+
return null if members.empty?
|
98
|
+
|
99
|
+
head = nil
|
100
|
+
members.reverse_each { |elem| head = Core::ConsCell.new(convert(elem), head) }
|
101
|
+
|
102
|
+
head
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
|
57
106
|
def null
|
58
107
|
Core::ConsCell.new(nil, nil)
|
59
108
|
end
|
60
109
|
|
110
|
+
# @return [Core::Succeed] A goal that unconditionally succeeds.
|
61
111
|
def succeed
|
62
|
-
|
112
|
+
goal_class.new(Core::Succeed.instance, [])
|
63
113
|
end
|
64
114
|
|
65
115
|
private
|
@@ -74,27 +124,83 @@ module MiniKraken
|
|
74
124
|
any_val = Core::AnyValue.allocate
|
75
125
|
any_val.instance_variable_set(:@rank, rank)
|
76
126
|
converted = any_val
|
127
|
+
elsif anArgument.id2name =~ /^"#[ft]"$/
|
128
|
+
converted = Core::KBoolean.new(anArgument)
|
77
129
|
else
|
78
130
|
converted = Core::KSymbol.new(anArgument)
|
79
131
|
end
|
132
|
+
when String
|
133
|
+
if anArgument =~ /^#[ft]$/
|
134
|
+
converted = Core::KBoolean.new(anArgument)
|
135
|
+
else
|
136
|
+
msg = "Internal error: undefined conversion for #{anArgument.class}"
|
137
|
+
raise StandardError, msg
|
138
|
+
end
|
139
|
+
when false, true
|
140
|
+
converted = Core::KBoolean.new(anArgument)
|
141
|
+
when Core::KBoolean
|
142
|
+
converted = anArgument
|
143
|
+
when Core::FormalRef
|
144
|
+
converted = anArgument
|
80
145
|
when Core::Goal
|
81
146
|
converted = anArgument
|
147
|
+
when Core::GoalTemplate
|
148
|
+
converted = anArgument
|
82
149
|
when Core::VariableRef
|
83
150
|
converted = anArgument
|
84
151
|
when Core::ConsCell
|
85
152
|
converted = anArgument
|
153
|
+
else
|
154
|
+
msg = "Internal error: undefined conversion for #{anArgument.class}"
|
155
|
+
raise StandardError, msg
|
86
156
|
end
|
87
157
|
|
88
158
|
converted
|
89
159
|
end
|
90
160
|
|
161
|
+
def default_mode
|
162
|
+
@dsl_mode = :default
|
163
|
+
@defrel_formals = nil
|
164
|
+
end
|
165
|
+
|
166
|
+
def goal_class
|
167
|
+
default_mode unless instance_variable_defined?(:@dsl_mode)
|
168
|
+
@dsl_mode == :default ? Core::Goal : Core::GoalTemplate
|
169
|
+
end
|
170
|
+
|
171
|
+
def start_defrel
|
172
|
+
@dsl_mode = :defrel
|
173
|
+
@defrel_formals = Set.new
|
174
|
+
end
|
175
|
+
|
176
|
+
def end_defrel
|
177
|
+
default_mode
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_defrel(aDefRelation)
|
181
|
+
@defrels = {} unless instance_variable_defined?(:@defrels)
|
182
|
+
@defrels[aDefRelation.name] = aDefRelation
|
183
|
+
end
|
184
|
+
|
91
185
|
def method_missing(mth, *args)
|
92
186
|
result = nil
|
93
187
|
|
94
188
|
begin
|
95
189
|
result = super(mth, *args)
|
96
190
|
rescue NameError
|
97
|
-
|
191
|
+
name = mth.id2name
|
192
|
+
@defrels = {} unless instance_variable_defined?(:@defrels)
|
193
|
+
if @defrels.include?(name)
|
194
|
+
def_relation = @defrels[name]
|
195
|
+
result = Core::Goal.new(def_relation, args.map { |el| convert(el) })
|
196
|
+
else
|
197
|
+
default_mode unless instance_variable_defined?(:@dsl_mode)
|
198
|
+
if @dsl_mode == :defrel && @defrel_formals.include?(name)
|
199
|
+
result = Core::FormalRef.new(name)
|
200
|
+
else
|
201
|
+
result = Core::VariableRef.new(name)
|
202
|
+
end
|
203
|
+
end
|
98
204
|
end
|
99
205
|
|
100
206
|
result
|
@@ -38,11 +38,9 @@ module MiniKraken
|
|
38
38
|
|
39
39
|
# @return [Array] A vector of assignment for each variable
|
40
40
|
def build_solution(outcome)
|
41
|
-
|
41
|
+
env.vars.values.map do |var|
|
42
42
|
outcome.successful? ? var.quote(outcome) : nil
|
43
43
|
end
|
44
|
-
|
45
|
-
sol
|
46
44
|
end
|
47
45
|
|
48
46
|
# Transform the solutions into sequence of conscells.
|
data/lib/mini_kraken/version.rb
CHANGED
data/mini_kraken.gemspec
CHANGED
@@ -9,6 +9,7 @@ module PkgExtending
|
|
9
9
|
def self.pkg_files(aPackage)
|
10
10
|
file_list = Dir[
|
11
11
|
'.rspec',
|
12
|
+
'.rubocop.yml',
|
12
13
|
'.travis.yml',
|
13
14
|
'Gemfile',
|
14
15
|
'Rakefile',
|
@@ -19,7 +20,8 @@ module PkgExtending
|
|
19
20
|
'bin/*.rb',
|
20
21
|
'lib/*.*',
|
21
22
|
'lib/**/*.rb',
|
22
|
-
'spec/**/*.rb'
|
23
|
+
'spec/**/*.rb',
|
24
|
+
'spec/.rubocop.yml'
|
23
25
|
]
|
24
26
|
aPackage.files = file_list
|
25
27
|
aPackage.test_files = Dir['spec/**/*_spec.rb']
|
@@ -38,8 +40,8 @@ Gem::Specification.new do |spec|
|
|
38
40
|
spec.authors = ['Dimitri Geshef']
|
39
41
|
spec.email = ['famished.tiger@yahoo.com']
|
40
42
|
|
41
|
-
spec.summary =
|
42
|
-
spec.description =
|
43
|
+
spec.summary = 'Implementation of Minikanren language in Ruby. WIP'
|
44
|
+
spec.description = 'Implementation of Minikanren language in Ruby. WIP'
|
43
45
|
spec.homepage = 'https://github.com/famished-tiger/mini_kraken'
|
44
46
|
spec.license = 'MIT'
|
45
47
|
|
@@ -47,6 +49,7 @@ Gem::Specification.new do |spec|
|
|
47
49
|
spec.bindir = 'exe'
|
48
50
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
49
51
|
spec.require_paths = ['lib']
|
52
|
+
spec.required_ruby_version = '~> 2.4'
|
50
53
|
|
51
54
|
PkgExtending.pkg_files(spec)
|
52
55
|
PkgExtending.pkg_documentation(spec)
|
data/spec/.rubocop.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
inherit_from: ../.rubocop.yml
|
2
|
+
|
3
|
+
# RSpec expectation lines can be very lenghty
|
4
|
+
Layout/LineLength:
|
5
|
+
Max: 99
|
6
|
+
|
7
|
+
# RSpec contexts can be very lenghty
|
8
|
+
Metrics/BlockLength:
|
9
|
+
Max: 1000
|
10
|
+
|
11
|
+
# RSpec modules can be very lenghty
|
12
|
+
Metrics/ModuleLength:
|
13
|
+
Max: 1000
|
data/spec/core/k_symbol_spec.rb
CHANGED
data/spec/glue/dsl_chap1_spec.rb
CHANGED
@@ -68,7 +68,7 @@ module MiniKraken
|
|
68
68
|
expect(result.car).to eq(:_0)
|
69
69
|
end
|
70
70
|
|
71
|
-
it 'passes frame 1:21
|
71
|
+
it "supports 'fresh' and passes frame 1:21" do
|
72
72
|
# Reasoned S2, frame 1:21
|
73
73
|
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
74
74
|
|
@@ -176,7 +176,7 @@ module MiniKraken
|
|
176
176
|
expect(result.car).to eq(cons(:_0, cons(:_1, cons(:_0))))
|
177
177
|
end
|
178
178
|
|
179
|
-
it 'passes frame 1:50
|
179
|
+
it "supports 'conj2' relation and passes frame 1:50" do
|
180
180
|
# Reasoned S2, frame 1:50
|
181
181
|
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
182
182
|
|
@@ -216,7 +216,7 @@ module MiniKraken
|
|
216
216
|
expect(result.car).to eq(:corn)
|
217
217
|
end
|
218
218
|
|
219
|
-
it 'passes frame 1:55
|
219
|
+
it "supports 'disj2' and passes frame 1:55" do
|
220
220
|
# Reasoned S2, frame 1:55
|
221
221
|
# (run* q (disj2 fail fail)) ;; => ()
|
222
222
|
|
@@ -301,7 +301,7 @@ module MiniKraken
|
|
301
301
|
# (== 'oil x))))) ;; => (olive _0 oil)
|
302
302
|
|
303
303
|
result = run_star('x', disj2(conj2(equals(:virgin, x), _fail),
|
304
|
-
|
304
|
+
disj2(equals(:olive, x), disj2(succeed, equals(:oil, x)))))
|
305
305
|
expect(result).to eq(cons(:olive, cons(:_0, cons(:oil))))
|
306
306
|
end
|
307
307
|
|
@@ -317,8 +317,8 @@ module MiniKraken
|
|
317
317
|
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
318
318
|
|
319
319
|
result = run_star('r', fresh('x', fresh('y',
|
320
|
-
conj2(equals(:split, x),
|
321
|
-
|
320
|
+
conj2(equals(:split, x),
|
321
|
+
conj2(equals(:pea, y), equals(cons(x, cons(y)), r))))))
|
322
322
|
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
323
323
|
end
|
324
324
|
|
@@ -396,8 +396,7 @@ module MiniKraken
|
|
396
396
|
# (== 'pea y))) ;; => ((split pea))
|
397
397
|
|
398
398
|
result = run_star(%w[x y], conj2(equals(:split, x), equals(:pea, y)))
|
399
|
-
expect(result.car
|
400
|
-
expect(result.car.cdr.car).to eq(:pea)
|
399
|
+
expect(result.car).to eq(list(:split, :pea))
|
401
400
|
end
|
402
401
|
|
403
402
|
it 'passes frame 1:76' do
|
@@ -410,10 +409,8 @@ module MiniKraken
|
|
410
409
|
result = run_star(%w[x y], disj2(
|
411
410
|
conj2(equals(:split, x), equals(:pea, y)),
|
412
411
|
conj2(equals(:red, x), equals(:bean, y))))
|
413
|
-
expect(result.car
|
414
|
-
expect(result.
|
415
|
-
expect(result.cdr.car.car).to eq(:red)
|
416
|
-
expect(result.cdr.car.cdr.car).to eq(:bean)
|
412
|
+
expect(result.car).to eq(list(:split, :pea))
|
413
|
+
expect(result.cdr.car).to eq(list(:red, :bean))
|
417
414
|
end
|
418
415
|
|
419
416
|
it 'passes frame 1:77' do
|
@@ -432,12 +429,8 @@ module MiniKraken
|
|
432
429
|
conj2(equals(:split, x), equals(:pea, y)),
|
433
430
|
conj2(equals(:red, x), equals(:bean, y))),
|
434
431
|
equals(cons(x, cons(y, cons(:soup))), r))))
|
435
|
-
expect(result.car
|
436
|
-
expect(result.
|
437
|
-
expect(result.car.cdr.cdr.car).to eq(:soup)
|
438
|
-
expect(result.cdr.car.car).to eq(:red)
|
439
|
-
expect(result.cdr.car.cdr.car).to eq(:bean)
|
440
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
|
432
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
433
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
441
434
|
end
|
442
435
|
|
443
436
|
it 'passes frame 1:78' do
|
@@ -451,15 +444,11 @@ module MiniKraken
|
|
451
444
|
|
452
445
|
result = run_star('r',
|
453
446
|
fresh(%w[x y], [disj2(
|
454
|
-
|
455
|
-
|
447
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
448
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
456
449
|
equals(cons(x, cons(y, cons(:soup))), r)]))
|
457
|
-
expect(result.car
|
458
|
-
expect(result.
|
459
|
-
expect(result.car.cdr.cdr.car).to eq(:soup)
|
460
|
-
expect(result.cdr.car.car).to eq(:red)
|
461
|
-
expect(result.cdr.car.cdr.car).to eq(:bean)
|
462
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
|
450
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
451
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
463
452
|
end
|
464
453
|
|
465
454
|
it 'passes frame 1:80' do
|
@@ -471,15 +460,11 @@ module MiniKraken
|
|
471
460
|
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
472
461
|
|
473
462
|
result = run_star(%w[x y z], [disj2(
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
expect(result.car
|
478
|
-
expect(result.
|
479
|
-
expect(result.car.cdr.cdr.car).to eq(:soup)
|
480
|
-
expect(result.cdr.car.car).to eq(:red)
|
481
|
-
expect(result.cdr.car.cdr.car).to eq(:bean)
|
482
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(:soup)
|
463
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
464
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
465
|
+
equals(:soup, z)])
|
466
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
467
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
483
468
|
end
|
484
469
|
|
485
470
|
it 'passes frame 1:81' do
|
@@ -489,8 +474,119 @@ module MiniKraken
|
|
489
474
|
# (== 'pea y)) ;; => ((split pea))
|
490
475
|
|
491
476
|
result = run_star(%w[x y], [equals(:split, x), equals(:pea, y)])
|
492
|
-
expect(result.car
|
493
|
-
|
477
|
+
expect(result.car).to eq(list(:split, :pea))
|
478
|
+
end
|
479
|
+
|
480
|
+
it "supports 'defrel' and passes frame 1:82" do
|
481
|
+
# Reasoned S2, frame 1:82
|
482
|
+
# (defrel (teacupo t)
|
483
|
+
# (disj2 (== 'tea t) (== 'cup t)))
|
484
|
+
|
485
|
+
result = defrel('teacupo', 't') do
|
486
|
+
disj2(equals(:tea, t), equals(:cup, t))
|
487
|
+
end
|
488
|
+
|
489
|
+
expect(result).to be_kind_of(Core::DefRelation)
|
490
|
+
expect(result.name).to eq('teacupo')
|
491
|
+
expect(result.formals.size).to eq(1)
|
492
|
+
expect(result.formals[0].name).to eq('t')
|
493
|
+
g_template = result.goal_template
|
494
|
+
expect(g_template).to be_kind_of(Core::GoalTemplate)
|
495
|
+
expect(g_template.relation).to eq(Core::Disj2.instance)
|
496
|
+
|
497
|
+
first_arg = g_template.args[0]
|
498
|
+
expect(first_arg).to be_kind_of(Core::GoalTemplate)
|
499
|
+
expect(first_arg.relation).to eq(Core::Equals.instance)
|
500
|
+
expect(first_arg.args[0]).to eq(:tea)
|
501
|
+
expect(first_arg.args[1]).to be_kind_of(Core::FormalRef)
|
502
|
+
expect(first_arg.args[1].name).to eq('t')
|
503
|
+
second_arg = g_template.args[1]
|
504
|
+
expect(second_arg).to be_kind_of(Core::GoalTemplate)
|
505
|
+
expect(second_arg.relation).to eq(Core::Equals.instance)
|
506
|
+
expect(second_arg.args[0]).to eq(:cup)
|
507
|
+
expect(second_arg.args[1]).to be_kind_of(Core::FormalRef)
|
508
|
+
expect(second_arg.args[1].name).to eq('t')
|
509
|
+
end
|
510
|
+
|
511
|
+
def defrel_teacupo
|
512
|
+
defrel('teacupo', 't') { disj2(equals(:tea, t), equals(:cup, t)) }
|
513
|
+
end
|
514
|
+
|
515
|
+
it "supports the invokation of a 'defrel' and passes frame 1:83" do
|
516
|
+
# Reasoned S2, frame 1:83
|
517
|
+
# (run* x
|
518
|
+
# (teacupo x)) ;; => ((tea cup))
|
519
|
+
|
520
|
+
defrel_teacupo
|
521
|
+
result = run_star('x', teacupo(x))
|
522
|
+
|
523
|
+
expect(result).to eq(cons(:tea, cons(:cup)))
|
524
|
+
end
|
525
|
+
|
526
|
+
it 'supports booleans and passes frame 1:84' do
|
527
|
+
# Reasoned S2, frame 1:84
|
528
|
+
# (run* (x y)
|
529
|
+
# (disj2
|
530
|
+
# (conj2 (teacupo x) (== #t y))
|
531
|
+
# (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
|
532
|
+
|
533
|
+
defrel_teacupo
|
534
|
+
result = run_star(%w[x y],
|
535
|
+
disj2(
|
536
|
+
conj2(teacupo(x), equals('#t', y)),
|
537
|
+
conj2(equals('#f', x), equals('#t', y))))
|
538
|
+
|
539
|
+
# Order of solutions differs from RS book
|
540
|
+
expect(result.car).to eq(cons(:tea, cons(true)))
|
541
|
+
expect(result.cdr.car).to eq(cons(:cup, cons(true)))
|
542
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
|
543
|
+
end
|
544
|
+
|
545
|
+
it 'passes frame 1:85' do
|
546
|
+
# Reasoned S2, frame 1:85
|
547
|
+
# (run* (x y)
|
548
|
+
# (teacupo x)
|
549
|
+
# (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
|
550
|
+
|
551
|
+
defrel_teacupo
|
552
|
+
result = run_star(%w[x y], [teacupo(x), teacupo(y)])
|
553
|
+
|
554
|
+
expect(result.car).to eq(cons(:tea, cons(:tea)))
|
555
|
+
expect(result.cdr.car).to eq(cons(:tea, cons(:cup)))
|
556
|
+
expect(result.cdr.cdr.car).to eq(cons(:cup, cons(:tea)))
|
557
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(:cup, cons(:cup)))
|
558
|
+
end
|
559
|
+
|
560
|
+
it 'passes frame 1:86' do
|
561
|
+
# Reasoned S2, frame 1:86
|
562
|
+
# (run* (x y)
|
563
|
+
# (teacupo x)
|
564
|
+
# (teacupo x)) ;; => ((tea _0)(cup _0))
|
565
|
+
|
566
|
+
defrel_teacupo
|
567
|
+
result = run_star(%w[x y], [teacupo(x), teacupo(x)])
|
568
|
+
|
569
|
+
expect(result.car).to eq(cons(:tea, cons(:_0)))
|
570
|
+
expect(result.cdr.car).to eq(cons(:cup, cons(:_0)))
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'passes frame 1:87' do
|
574
|
+
# Reasoned S2, frame 1:87
|
575
|
+
# (run* (x y)
|
576
|
+
# (disj2
|
577
|
+
# (conj2 (teacupo x) (teacupo x))
|
578
|
+
# (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
579
|
+
|
580
|
+
defrel_teacupo
|
581
|
+
result = run_star(%w[x y], disj2(
|
582
|
+
conj2(teacupo(x), teacupo(x)),
|
583
|
+
conj2(equals('#f', x), teacupo(y))))
|
584
|
+
|
585
|
+
# Order of solutions differs from RS book
|
586
|
+
expect(result.car).to eq(cons(:tea, cons(:_0)))
|
587
|
+
expect(result.cdr.car).to eq(cons(:cup, cons(:_0)))
|
588
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(:tea)))
|
589
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(:cup)))
|
494
590
|
end
|
495
591
|
end # context
|
496
592
|
end # describe
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_kraken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.01
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07
|
11
|
+
date: 2020-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,6 +61,7 @@ extra_rdoc_files:
|
|
61
61
|
- README.md
|
62
62
|
files:
|
63
63
|
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
64
65
|
- ".travis.yml"
|
65
66
|
- CHANGELOG.md
|
66
67
|
- Gemfile
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/mini_kraken/glue/run_star_expression.rb
|
110
111
|
- lib/mini_kraken/version.rb
|
111
112
|
- mini_kraken.gemspec
|
113
|
+
- spec/.rubocop.yml
|
112
114
|
- spec/core/association_spec.rb
|
113
115
|
- spec/core/association_walker_spec.rb
|
114
116
|
- spec/core/conde_spec.rb
|
@@ -146,9 +148,9 @@ require_paths:
|
|
146
148
|
- lib
|
147
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
148
150
|
requirements:
|
149
|
-
- - "
|
151
|
+
- - "~>"
|
150
152
|
- !ruby/object:Gem::Version
|
151
|
-
version: '
|
153
|
+
version: '2.4'
|
152
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
155
|
requirements:
|
154
156
|
- - ">="
|