rubylog 2.0.1 → 2.1.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.
Files changed (81) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +10 -0
  3. data/README.rdoc +1 -1
  4. data/RELEASE_NOTES.rdoc +7 -4
  5. data/VERSION +1 -1
  6. data/{examples → benchmark}/benchmark.rb +1 -0
  7. data/{examples → benchmark}/benchmark/compiled_not_indexed.rb +0 -0
  8. data/{examples → benchmark}/benchmark/compiled_sequence_indexed.rb +0 -0
  9. data/{examples → benchmark}/benchmark/indexed_procedure.rb +0 -0
  10. data/{examples → benchmark}/benchmark/prolog.rb +0 -0
  11. data/benchmark/benchmark/pure.rb +28 -0
  12. data/bin/rubylog +14 -0
  13. data/examples/a_plus_b.rb +2 -2
  14. data/examples/dcg.rb +22 -26
  15. data/examples/dcg2.rb +25 -30
  16. data/examples/divisors.rb +1 -3
  17. data/examples/factorial.rb +8 -15
  18. data/examples/file_search.rb +14 -13
  19. data/examples/hanoi.rb +1 -3
  20. data/examples/hu/csaladfa.rb +0 -4
  21. data/examples/n_queens.rb +17 -22
  22. data/examples/palindrome_detection.rb +1 -2
  23. data/examples/parsing.rb +19 -23
  24. data/examples/permutation.rb +1 -3
  25. data/examples/primality_by_division.rb +2 -2
  26. data/examples/sieve_of_eratosthenes.rb +2 -2
  27. data/examples/string_interpolation.rb +0 -3
  28. data/examples/tracing.rb +0 -4
  29. data/lib/rubylog/builtins/assumption.rb +2 -1
  30. data/lib/rubylog/builtins/file_system.rb +1 -1
  31. data/lib/rubylog/default_context.rb +3 -5
  32. data/lib/rubylog/mixins/kernel.rb +9 -1
  33. data/lib/rubylog/rubylog_files.rb +7 -0
  34. data/rubylog.gemspec +17 -22
  35. data/spec/inriasuite_spec.rb +851 -847
  36. data/spec/integration/dsl_spec.rb +32 -29
  37. data/spec/rspec/rubylog_spec.rb +46 -52
  38. data/spec/rubylog/assertable_spec.rb +92 -90
  39. data/spec/rubylog/builtins/arithmetics_spec.rb +92 -90
  40. data/spec/rubylog/builtins/assumption_spec.rb +59 -57
  41. data/spec/rubylog/builtins/ensure_spec.rb +6 -4
  42. data/spec/rubylog/builtins/file_system_spec.rb +41 -39
  43. data/spec/rubylog/builtins/logic_spec.rb +308 -306
  44. data/spec/rubylog/builtins/reflection_spec.rb +31 -29
  45. data/spec/rubylog/builtins/term_spec.rb +62 -60
  46. data/spec/rubylog/context_modules/demonstration_spec.rb +108 -106
  47. data/spec/rubylog/context_modules/predicates_spec.rb +29 -27
  48. data/spec/rubylog/context_modules/thats_spec.rb +77 -75
  49. data/spec/rubylog/dsl/array_splat_spec.rb +11 -9
  50. data/spec/rubylog/dsl/indicators_spec.rb +23 -21
  51. data/spec/rubylog/dsl/primitives_spec.rb +30 -28
  52. data/spec/rubylog/errors_spec.rb +13 -11
  53. data/spec/rubylog/interfaces/term_spec.rb +78 -76
  54. data/spec/rubylog/mixins/array_spec.rb +60 -58
  55. data/spec/rubylog/mixins/composite_term_spec.rb +55 -53
  56. data/spec/rubylog/mixins/proc_spec.rb +48 -46
  57. data/spec/rubylog/mixins/string_spec.rb +45 -43
  58. data/spec/rubylog/mixins/symbol_spec.rb +7 -5
  59. data/spec/rubylog/procedure_spec.rb +8 -6
  60. data/spec/rubylog/rule_spec.rb +10 -8
  61. data/spec/rubylog/structure_spec.rb +73 -71
  62. data/spec/rubylog/term_spec.rb +5 -3
  63. data/spec/rubylog/tracing_spec.rb +35 -33
  64. data/spec/rubylog/variable_spec.rb +249 -247
  65. data/spec/spec_helper.rb +4 -0
  66. metadata +54 -43
  67. data/examples/benchmark/pure.rb +0 -26
  68. data/examples/checkmate.rb +0 -88
  69. data/examples/combination.rb +0 -17
  70. data/examples/directory_structure_logic.rb +0 -17
  71. data/examples/dirlist.rb +0 -4
  72. data/examples/enumerators.rb +0 -30
  73. data/examples/hello.rb +0 -17
  74. data/examples/mice.rb +0 -92
  75. data/examples/mice2.rb +0 -37
  76. data/examples/object_oriented.rb +0 -14
  77. data/examples/prefix.rb +0 -13
  78. data/examples/primitives.rb +0 -26
  79. data/examples/sudoku.rb +0 -17
  80. data/spec/integration/theory_as_module_spec.rb +0 -20
  81. data/spec/integration/theory_as_module_with_include_spec.rb +0 -14
data/Gemfile CHANGED
@@ -7,4 +7,6 @@ group :development do
7
7
  gem "bundler", ">= 1.0.0"
8
8
  gem "jeweler", ">= 1.8.3"
9
9
  gem "simplecov", :require => false
10
+ gem "guard"
11
+ gem "guard-rspec"
10
12
  end
data/Gemfile.lock CHANGED
@@ -3,12 +3,19 @@ GEM
3
3
  specs:
4
4
  diff-lcs (1.2.4)
5
5
  git (1.2.5)
6
+ guard (1.4.0)
7
+ listen (>= 0.4.2)
8
+ thor (>= 0.14.6)
9
+ guard-rspec (2.0.0)
10
+ guard (>= 1.1)
11
+ rspec (~> 2.11)
6
12
  jeweler (1.8.4)
7
13
  bundler (~> 1.0)
8
14
  git (>= 1.2.5)
9
15
  rake
10
16
  rdoc
11
17
  json (1.7.7)
18
+ listen (0.5.2)
12
19
  multi_json (1.7.2)
13
20
  rake (10.0.4)
14
21
  rdoc (4.0.1)
@@ -26,6 +33,7 @@ GEM
26
33
  multi_json (~> 1.0)
27
34
  simplecov-html (~> 0.7.1)
28
35
  simplecov-html (0.7.1)
36
+ thor (0.18.1)
29
37
  yard (0.8.6.1)
30
38
 
31
39
  PLATFORMS
@@ -33,6 +41,8 @@ PLATFORMS
33
41
 
34
42
  DEPENDENCIES
35
43
  bundler (>= 1.0.0)
44
+ guard
45
+ guard-rspec
36
46
  jeweler (>= 1.8.3)
37
47
  rspec (>= 2.8.0, < 3)
38
48
  ruby-prof
data/README.rdoc CHANGED
@@ -19,7 +19,7 @@ First, install the gem
19
19
 
20
20
  or, if you use +bundler+, add this line to your +Gemfile+:
21
21
 
22
- gem 'rubylog', '~>2.0'
22
+ gem 'rubylog', '~>2.1'
23
23
 
24
24
 
25
25
  === The context
data/RELEASE_NOTES.rdoc CHANGED
@@ -1,8 +1,11 @@
1
- == Version 2.1 (planned)
1
+ == Planned features
2
+ * <tt>solve</tt> without a block returns an enumerator
3
+ * warning for singleton variables
4
+ * <tt>nonvar</tt> predicate
5
+
6
+ == Version 2.1
2
7
  * New features
3
- * solve without a block returns an enumerator
4
- * warning for singleton variables
5
- * predicate for checking bound/unbound variables
8
+ * Works with Ruby 1.9.3 and 2.0 (only <tt>module X; extend Rubylog::Context</tt> syntax)
6
9
 
7
10
  == Version 2.0.1
8
11
  * Bug fixes
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.1
1
+ 2.1.0
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env ruby
1
2
  # benchmark
2
3
  #
3
4
  # The task is to collect all grandparent-granchild relationships in a family
File without changes
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+ require "rubylog"
3
+
4
+ module FamilyTree
5
+ extend Rubylog::Context
6
+ predicate_for $person_class, ".parent_of() .grandparent_of()"
7
+
8
+ def make_tree(parent, levels)
9
+ return if levels.zero?
10
+
11
+ children = (1..DEGREES).map{random_person}
12
+
13
+ children.each do |child|
14
+ # add relationship
15
+ parent.parent_of!(child)
16
+ end
17
+
18
+ children.each do |child|
19
+ # make sub-tree
20
+ make_tree(child, levels-1)
21
+ end
22
+ end
23
+
24
+ make_tree(random_person, LEVELS)
25
+
26
+ A.grandparent_of(B).if A.parent_of(X).and X.parent_of(B)
27
+
28
+ end
data/bin/rubylog ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubylog"
3
+ require "rubylog/rubylog_files"
4
+
5
+ if ARGV.empty?
6
+ filename = '-'
7
+ source = $stdin.read
8
+ source = Rubylog::RubylogFiles.convert_source(source)
9
+ eval(source, TOPLEVEL_BINDING, filename, 1)
10
+ else
11
+ load_rubylog ARGV.shift
12
+ end
13
+
14
+
data/examples/a_plus_b.rb CHANGED
@@ -1,6 +1,6 @@
1
- require "rubylog"
2
- extend Rubylog::Context
1
+ # Read two integers in each line of the input. Write the sum of each pair to the outuput.
3
2
 
4
3
  "#{A} #{B}".in{$stdin.readlines}.each do
5
4
  puts A.to_i + B.to_i
6
5
  end
6
+
data/examples/dcg.rb CHANGED
@@ -1,36 +1,32 @@
1
- require "rubylog"
2
- # This is a quick and dirty solution to replace Prolog's DCG syntax.
1
+ # This is a simple solution to replace Prolog's DCG syntax.
3
2
  # It is slow for long inputs. See examples/dcg2.rb for a more efficient algorithm (the same as Prolog's DCG).
4
3
 
5
- rubylog do
6
- predicate_for Array, ".sentence", ".subject", ".object", ".nominal_phrase", ".noun", ".verb", ".article"
4
+ predicate_for Array, ".sentence", ".subject", ".object", ".nominal_phrase", ".noun", ".verb", ".article"
7
5
 
8
- [*S,*V,*O].sentence.if S.subject.and V.verb.and O.object
9
- S.subject.if S.nominal_phrase
10
- O.object .if O.nominal_phrase
11
- [*A,*N].nominal_phrase.if A.article.and N.noun
6
+ [*S,*V,*O].sentence.if S.subject.and V.verb.and O.object
7
+ S.subject.if S.nominal_phrase
8
+ O.object .if O.nominal_phrase
9
+ [*A,*N].nominal_phrase.if A.article.and N.noun
12
10
 
13
- %w(a).article!
14
- %w(the).article!
11
+ %w(a).article!
12
+ %w(the).article!
15
13
 
16
- %w(dog).noun!
17
- %w(cat).noun!
18
- %w(mouse).noun!
14
+ %w(dog).noun!
15
+ %w(cat).noun!
16
+ %w(mouse).noun!
19
17
 
20
- %w(chases).verb!
21
- %w(eats).verb!
18
+ %w(chases).verb!
19
+ %w(eats).verb!
22
20
 
23
- def check_passed goal; end
21
+ def check_passed goal; end
24
22
 
25
- check %w(dog).noun
26
- check %w(a dog).nominal_phrase
27
- check %w(dog).nominal_phrase.false
28
- check %w(the dog chases a cat).sentence
29
- check %w(the dog chases a cat stuff).sentence.false
30
- check %w(dog chases cat).sentence.false
31
- check { %W(the #{S} chases the #{O}).sentence.map{[S,O]}.count == 9 }
23
+ check %w(dog).noun
24
+ check %w(a dog).nominal_phrase
25
+ check %w(dog).nominal_phrase.false
26
+ check %w(the dog chases a cat).sentence
27
+ check %w(the dog chases a cat stuff).sentence.false
28
+ check %w(dog chases cat).sentence.false
29
+ check { %W(the #{S} chases the #{O}).sentence.map{[S,O]}.count == 9 }
32
30
 
33
- puts *S.sentence.map{S.join(" ")}
31
+ puts *S.sentence.map{S.join(" ")}
34
32
 
35
-
36
- end
data/examples/dcg2.rb CHANGED
@@ -1,42 +1,37 @@
1
1
  # This is an example of the same algorithm that Prolog's DCG syntax generates.
2
2
  #
3
3
 
4
- $:.unshift File.dirname(__FILE__)+"/../lib"
5
- require 'rubylog'
6
4
 
7
- rubylog do
8
- predicate_for Array, ".sentence()", ".subject()", ".object()", ".nominal_phrase()", ".noun()", ".verb()", ".article()"
5
+ predicate_for Array, ".sentence()", ".subject()", ".object()", ".nominal_phrase()", ".noun()", ".verb()", ".article()"
9
6
 
10
- # sentence --> subject, verb, object
11
- Se.sentence(L3).if Se.subject(L1).and L1.verb(L2).and L2.object(L3)
12
- # subject --> nominal_phrase
13
- S.subject(L1).if S.nominal_phrase(L1)
14
- # object --> nominal_phrase
15
- O.object(L1) .if O.nominal_phrase(L1)
16
- # nominal_phrase --> article, noun
17
- N.nominal_phrase(L2).if N.article(L1).and L1.noun(L2)
7
+ # sentence --> subject, verb, object
8
+ Se.sentence(L3).if Se.subject(L1).and L1.verb(L2).and L2.object(L3)
9
+ # subject --> nominal_phrase
10
+ S.subject(L1).if S.nominal_phrase(L1)
11
+ # object --> nominal_phrase
12
+ O.object(L1) .if O.nominal_phrase(L1)
13
+ # nominal_phrase --> article, noun
14
+ N.nominal_phrase(L2).if N.article(L1).and L1.noun(L2)
18
15
 
19
- ["a",*L1].article! L1
20
- ["the",*L1].article! L1
16
+ ["a",*L1].article! L1
17
+ ["the",*L1].article! L1
21
18
 
22
- ["dog",*L1].noun! L1
23
- ["cat",*L1].noun! L1
24
- ["mouse",*L1].noun! L1
19
+ ["dog",*L1].noun! L1
20
+ ["cat",*L1].noun! L1
21
+ ["mouse",*L1].noun! L1
25
22
 
26
- ["chases",*L1].verb! L1
27
- ["eats",*L1].verb! L1
23
+ ["chases",*L1].verb! L1
24
+ ["eats",*L1].verb! L1
28
25
 
29
- def check_passed goal; end
26
+ def check_passed goal; end
30
27
 
31
- check %w(dog).noun([])
32
- check %w(a dog).nominal_phrase([])
33
- check %w(dog).nominal_phrase(ANY).false
34
- check %w(the dog chases a cat).sentence([])
35
- check %w(the dog chases a cat stuff).sentence(["stuff"])
36
- check %w(dog chases cat).sentence(ANY).false
37
- check { %W(the #{S} chases the #{O}).sentence([]).map{[S,O]}.count == 9 }
28
+ check %w(dog).noun([])
29
+ check %w(a dog).nominal_phrase([])
30
+ check %w(dog).nominal_phrase(ANY).false
31
+ check %w(the dog chases a cat).sentence([])
32
+ check %w(the dog chases a cat stuff).sentence(["stuff"])
33
+ check %w(dog chases cat).sentence(ANY).false
34
+ check { %W(the #{S} chases the #{O}).sentence([]).map{[S,O]}.count == 9 }
38
35
 
39
- puts *S.sentence([]).map{S.join(" ")}
36
+ puts *S.sentence([]).map{S.join(" ")}
40
37
 
41
-
42
- end
data/examples/divisors.rb CHANGED
@@ -1,4 +1,2 @@
1
- $:.unshift File.dirname(__FILE__)+"/../lib"
2
- require "rubylog"
3
-
1
+ # Outputs the number of pairs of divisors of 672
4
2
  p rubylog { P.is(672).and A.in{1..P}.and P.product_of(A,B).and{A<=B} }.count
@@ -1,17 +1,10 @@
1
- $:.unshift File.dirname(__FILE__)+"/../lib"
2
- require 'rubylog'
3
-
4
- rubylog do
5
- predicate_for Integer, ".factorial()"
6
-
7
- 0.factorial! 1
8
- N[thats > 0].factorial(K).if \
9
- N.sum_of(N1,1).
10
- and N1.factorial(K1).
11
- and K.product_of(K1,N)
12
-
13
- 7.factorial(N).solve {puts N}
14
- end
15
-
1
+ # Factorial
2
+ predicate_for Integer, ".factorial()"
16
3
 
4
+ 0.factorial! 1
5
+ N[thats > 0].factorial(K).if \
6
+ N.sum_of(N1,1).
7
+ and N1.factorial(K1).
8
+ and K.product_of(K1,N)
17
9
 
10
+ 7.factorial(N).solve {puts N}
@@ -1,16 +1,17 @@
1
- require "rubylog"
2
- extend Rubylog::Context
1
+ # Outputs which source files have and which source files do not have a test.
2
+ #
3
3
 
4
- [true,false].each do |b|
5
- puts "Files which #{b ? 'have' : 'do not have'} spec:"
4
+ predicate_for String, ".libfile .specfile"
6
5
 
7
- "lib/#{X}.rb".file_in("lib/**").each do
8
- if b == "spec/#{X}_spec.rb".file_in?("spec/**")
9
- puts X
10
- end
11
- end
12
-
13
- puts
14
-
15
- end
6
+ L.libfile.if "lib/#{L}.rb".file_in("lib/**")
7
+ L.specfile.if "spec/#{L}_spec.rb".file_in("spec/**")
16
8
 
9
+ puts "Libs which have spec:"
10
+ L.libfile.and(L.specfile).each { puts L }
11
+ puts
12
+ puts "Libs which do not have spec:"
13
+ L.libfile.and(L.specfile.false).each { puts L }
14
+ puts
15
+ puts "Specs which do not have lib:"
16
+ L.specfile.and(L.libfile.false).each { puts L }
17
+ puts
data/examples/hanoi.rb CHANGED
@@ -1,6 +1,4 @@
1
- $:.unshift File.dirname(__FILE__)+"/../lib"
2
- require "rubylog"
3
- extend Rubylog::Context
1
+ # Hanoi tower solution
4
2
 
5
3
  predicate_for Integer, ".move(,,)", ".hanoi"
6
4
 
@@ -1,7 +1,3 @@
1
- # encoding: UTF-8
2
- require "rubylog"
3
- extend Rubylog::Context
4
-
5
1
  predicate_for String, ".parent_of() .grandparent_of()"
6
2
 
7
3
  # ki kinek a szülője
data/examples/n_queens.rb CHANGED
@@ -1,32 +1,27 @@
1
- $:.unshift File.dirname(__FILE__)+"/../lib"
2
- require "rubylog"
1
+ predicate_for Integer, ".on(,)", ".attacks(,)", ".placed"
2
+ predicate ":arranged"
3
3
 
4
- rubylog do
5
- predicate_for Integer, ".on(,)", ".attacks(,)", ".placed"
6
- predicate ":arranged"
4
+ N=7
7
5
 
8
- N=7
6
+ A.attacks(R,ANY_C).if A.on(R,ANY_C)
7
+ A.attacks(ANY_R,C).if A.on(ANY_R,C)
8
+ A.attacks(R2,C2).if A.on(R1,C1).and {R1-C1==R2-C2}
9
+ A.attacks(R2,C2).if A.on(R1,C1).and {R1+C1==R2+C2}
9
10
 
10
- A.attacks(R,ANY_C).if A.on(R,ANY_C)
11
- A.attacks(ANY_R,C).if A.on(ANY_R,C)
12
- A.attacks(R2,C2).if A.on(R1,C1).and {R1-C1==R2-C2}
13
- A.attacks(R2,C2).if A.on(R1,C1).and {R1+C1==R2+C2}
11
+ A.placed.if \
12
+ C.in(1..N).and(B.on(ANY,ANY).none(B.attacks(A,C))).and A.on(A,C).assumed
14
13
 
15
- A.placed.if \
16
- C.in(1..N).and(B.on(ANY,ANY).none(B.attacks(A,C))).and A.on(A,C).assumed
14
+ :arranged.if every A.in(1..N), A.placed
17
15
 
18
- :arranged.if every A.in(1..N), A.placed
19
-
20
- :arranged.solve do
21
- L.in(1..N).each do
22
- M.in(1..N).each do
23
- print ANY.on?(L,M) ? "X" : "."
24
- end
25
- puts
16
+ :arranged.solve do
17
+ # draw board
18
+ L.in(1..N).each do
19
+ M.in(1..N).each do
20
+ print ANY.on?(L,M) ? "X" : "."
26
21
  end
27
22
  puts
28
23
  end
29
-
30
-
24
+ puts
31
25
  end
32
26
 
27
+
@@ -1,5 +1,4 @@
1
- require "rubylog"
2
- extend Rubylog::Context
1
+ # Palindrome checking with guards
3
2
 
4
3
  predicate_for String, ".palindrome"
5
4
 
data/examples/parsing.rb CHANGED
@@ -1,29 +1,25 @@
1
- $:.unshift File.dirname(__FILE__)+"/../lib"
2
- require "rubylog"
3
1
  require "readline"
4
2
 
5
- rubylog do
6
- predicate_for String, ".term()", ".expr()", ".atom()"
3
+ predicate_for String, ".term()", ".expr()", ".atom()"
7
4
 
8
- "#{A}+#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I+J}
9
- "#{A}-#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I-J}
10
- A.expr(K).if A.term(K)
11
- "#{A}*#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I*J}
12
- "#{A}/#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I/J}
13
- A.term(K).if A.atom(K)
14
- A[/\A[0-9]+\z/].atom(K).if K.is{A.to_i}
15
- "(#{A})".atom(K).if A.expr(K)
5
+ "#{A}+#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I+J}
6
+ "#{A}-#{B}".expr(K).if A.expr(I).and B.term(J).and K.is{I-J}
7
+ A.expr(K).if A.term(K)
8
+ "#{A}*#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I*J}
9
+ "#{A}/#{B}".term(K).if A.atom(I).and B.term(J).and K.is{I/J}
10
+ A.term(K).if A.atom(K)
11
+ A[/\A[0-9]+\z/].atom(K).if K.is{A.to_i}
12
+ "(#{A})".atom(K).if A.expr(K)
16
13
 
17
- check "5".expr(5)
18
- check "5+3*2".expr(11)
19
- check "1+2+3+4".expr(10)
20
- check "(5+3)/2".expr(4)
21
- check "(5+3(5)/2".expr(ANY).false
22
-
23
- puts
24
- while k = Readline.readline("> ", true)
25
- k.chomp!
26
- puts k.expr(X).map{X}.first || "error"
27
- end
14
+ check "5".expr(5)
15
+ check "5+3*2".expr(11)
16
+ check "1+2+3+4".expr(10)
17
+ check "(5+3)/2".expr(4)
18
+ check "(5+3(5)/2".expr(ANY).false
28
19
 
20
+ puts
21
+ while k = Readline.readline("> ", true)
22
+ k.chomp!
23
+ puts k.expr(X).map{X}.first || "error"
29
24
  end
25
+