rubylog 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+