pure 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/CHANGES.rdoc +7 -0
  2. data/MANIFEST +44 -20
  3. data/README.rdoc +553 -16
  4. data/Rakefile +25 -2
  5. data/devel/jumpstart.rb +606 -253
  6. data/install.rb +1 -2
  7. data/lib/pure.rb +38 -16
  8. data/lib/pure/bundled_parsers.rb +4 -0
  9. data/lib/pure/bundled_plugin.rb +49 -0
  10. data/lib/pure/compiler/ruby_parser.rb +63 -0
  11. data/lib/pure/delegate.rb +16 -0
  12. data/lib/pure/driver.rb +33 -0
  13. data/lib/pure/dsl.rb +2 -0
  14. data/lib/pure/dsl_definition.rb +11 -0
  15. data/lib/pure/error.rb +89 -0
  16. data/lib/pure/extracted_functions.rb +11 -0
  17. data/lib/pure/extractor.rb +59 -0
  18. data/lib/pure/names.rb +9 -0
  19. data/lib/pure/native_worker.rb +27 -0
  20. data/lib/pure/parser/impl/base_parser.rb +21 -0
  21. data/lib/pure/parser/impl/internal.rb +31 -0
  22. data/lib/pure/parser/impl/ripper.rb +96 -0
  23. data/lib/pure/parser/impl/ruby_parser.rb +77 -0
  24. data/lib/pure/parser/internal.rb +4 -0
  25. data/lib/pure/parser/ripper.rb +2 -0
  26. data/lib/pure/parser/ruby_parser.rb +2 -0
  27. data/lib/pure/pure.rb +32 -0
  28. data/lib/pure/pure_module.rb +141 -0
  29. data/lib/pure/util.rb +15 -0
  30. data/lib/pure/version.rb +4 -0
  31. data/spec/compiler_ruby_parser_spec.rb +79 -0
  32. data/spec/compute_overrides_spec.rb +99 -0
  33. data/spec/compute_spec.rb +86 -0
  34. data/spec/compute_thread_spec.rb +29 -0
  35. data/spec/compute_timed_spec.rb +40 -0
  36. data/spec/delegate_spec.rb +141 -0
  37. data/spec/fstat_example.rb +26 -0
  38. data/spec/parser_sexp_spec.rb +100 -0
  39. data/spec/parser_spec.rb +18 -31
  40. data/spec/pure_combine_spec.rb +77 -0
  41. data/spec/pure_def_spec.rb +186 -0
  42. data/spec/pure_define_method_spec.rb +24 -0
  43. data/spec/pure_eval_spec.rb +18 -0
  44. data/spec/pure_fun_spec.rb +243 -0
  45. data/spec/pure_nested_spec.rb +35 -0
  46. data/spec/pure_parser_spec.rb +50 -0
  47. data/spec/pure_spec.rb +81 -0
  48. data/spec/pure_spec_base.rb +106 -0
  49. data/spec/pure_splat_spec.rb +18 -0
  50. data/spec/pure_two_defs_spec.rb +20 -0
  51. data/spec/pure_worker_spec.rb +33 -0
  52. data/spec/readme_spec.rb +36 -32
  53. data/spec/splat_spec.rb +12 -11
  54. data/spec/worker_spec.rb +89 -0
  55. metadata +157 -41
  56. data/devel/jumpstart/lazy_attribute.rb +0 -38
  57. data/devel/jumpstart/ruby.rb +0 -44
  58. data/devel/jumpstart/simple_installer.rb +0 -85
  59. data/lib/pure/pure_private/creator.rb +0 -27
  60. data/lib/pure/pure_private/driver.rb +0 -48
  61. data/lib/pure/pure_private/error.rb +0 -32
  62. data/lib/pure/pure_private/extractor.rb +0 -79
  63. data/lib/pure/pure_private/extractor_ripper.rb +0 -95
  64. data/lib/pure/pure_private/extractor_ruby_parser.rb +0 -47
  65. data/lib/pure/pure_private/function_database.rb +0 -10
  66. data/lib/pure/pure_private/singleton_features.rb +0 -67
  67. data/lib/pure/pure_private/util.rb +0 -23
  68. data/spec/basic_spec.rb +0 -38
  69. data/spec/combine_spec.rb +0 -62
  70. data/spec/common.rb +0 -44
  71. data/spec/error_spec.rb +0 -146
  72. data/spec/fun_spec.rb +0 -122
  73. data/spec/lazy_spec.rb +0 -22
  74. data/spec/subseqent_spec.rb +0 -42
  75. data/spec/timed_spec.rb +0 -30
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ describe "with nested defs" do
5
+ it "should work with different names" do
6
+ Class.new do
7
+ def f(n)
8
+ pure do
9
+ def g(h)
10
+ h**2
11
+ end
12
+ fun :h do
13
+ n
14
+ end
15
+ end.compute(Pure::NativeWorker).g
16
+ end
17
+ end.new.f(5).should == 25
18
+ end
19
+
20
+ it "should work with the same name" do
21
+ Class.new do
22
+ def f(n)
23
+ pure do
24
+ def f(h)
25
+ h**2
26
+ end
27
+ fun :h do
28
+ n
29
+ end
30
+ end.compute(Pure::NativeWorker).f
31
+ end
32
+ end.new.f(5).should == 25
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "Pure.parser" do
4
+ it "should return the current parser" do
5
+ Pure.parser.should_not == nil
6
+ end
7
+
8
+ it "should have a default" do
9
+ Pure.parser = nil
10
+ pure do
11
+ def f
12
+ end
13
+ end.compute(Pure::NativeWorker).f
14
+ Pure.parser.should_not == nil
15
+ end
16
+
17
+ it "should be changed with Pure.parser=" do
18
+ lambda {
19
+ mod = pure do
20
+ def f
21
+ end
22
+ end
23
+ }.should_not raise_error
24
+ previous = Pure.parser
25
+ Pure.parser = "junk"
26
+ begin
27
+ lambda {
28
+ mod = pure do
29
+ def f
30
+ end
31
+ end
32
+ }.should raise_error
33
+ ensure
34
+ Pure.parser = previous
35
+ end
36
+ end
37
+
38
+ it "should raise error when no parser found" do
39
+ source = File.dirname(__FILE__) + "/../lib/pure/parser"
40
+ dest = source + "-tmp"
41
+ FileUtils.mv(source, dest)
42
+ begin
43
+ lambda {
44
+ Pure::BundledParsers.find_default
45
+ }.should raise_error(Pure::NoParserError, "no parser found")
46
+ ensure
47
+ FileUtils.mv(dest, source)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ require 'jumpstart'
4
+
5
+ describe "pure" do
6
+ it "should not be available without require 'pure/dsl'" do
7
+ code = %{
8
+ begin
9
+ pure do
10
+ end
11
+ rescue Exception => e
12
+ unless e.is_a?(NameError)
13
+ raise 'expected name error'
14
+ end
15
+ unless e.message =~ %r!undefined method \`pure\'!
16
+ raise 'unmatched message'
17
+ end
18
+ end
19
+ }
20
+ lambda {
21
+ Jumpstart::Ruby.run("-e", code)
22
+ }.should_not raise_error
23
+ end
24
+
25
+ it "should be an alias of Pure.define" do
26
+ Pure.define do
27
+ def f
28
+ 33
29
+ end
30
+ end.compute(4).f.should == 33
31
+ end
32
+
33
+ it "should not allow `fun' outside of block" do
34
+ lambda {
35
+ pure do
36
+ end.fun :x do
37
+ 33
38
+ end
39
+ }.should raise_error(NoMethodError)
40
+ end
41
+
42
+ describe "with subsequent `def' definitions" do
43
+ it "should be accepted" do
44
+ mod = pure do
45
+ def f
46
+ 33
47
+ end
48
+ end
49
+
50
+ mod.compute(4).f.should eql(33)
51
+
52
+ mod.module_eval do
53
+ def g
54
+ 44
55
+ end
56
+ end
57
+
58
+ mod.compute(4).g.should eql(44)
59
+ end
60
+ end
61
+
62
+ describe "with subsequent `fun' definitions" do
63
+ it "should be accepted" do
64
+ mod = pure do
65
+ fun :f do
66
+ 33
67
+ end
68
+ end
69
+
70
+ mod.compute(4).f.should eql(33)
71
+
72
+ mod.module_eval do
73
+ fun :g do
74
+ 44
75
+ end
76
+ end
77
+
78
+ mod.compute(4).g.should eql(44)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,106 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../devel'
3
+
4
+ require 'pure/dsl'
5
+ require 'spec/autorun'
6
+
7
+ TOPLEVEL_INSTANCE = self
8
+
9
+ #
10
+ # verify compilers
11
+ #
12
+ module CompilerWorker
13
+ class Base
14
+ attr_reader :num_parallel
15
+
16
+ def define_function(spec)
17
+ lambda { |*args|
18
+ self.class.compiler.new.evaluate_function(spec, *args)
19
+ }
20
+ end
21
+
22
+ def define_function_begin(pure_module, num_parallel)
23
+ @num_parallel = num_parallel || self.class.num_parallel
24
+ end
25
+
26
+ def define_function_end
27
+ end
28
+
29
+ class << self
30
+ attr_accessor :num_parallel
31
+ attr_reader :compiler
32
+ end
33
+ end
34
+
35
+ Pure::BundledParsers.available.values.map { |parser|
36
+ parser.compiler rescue nil
37
+ }.compact.each { |path, name|
38
+ names = name.split("::")
39
+ worker = Class.new Base do
40
+ require path
41
+ @compiler = names.inject(Object) { |mod, name|
42
+ mod.const_get(name)
43
+ }
44
+ end
45
+ const_set(names.last, worker)
46
+ }
47
+ end
48
+
49
+ module Spec::Example::ExampleGroupMethods
50
+ alias_method :describe__original, :describe
51
+
52
+ def describe(*args, &block)
53
+ if args[1] and args[1][:scope] == TOPLEVEL_INSTANCE
54
+ Pure::BundledParsers.available.each { |parser_path, parser|
55
+ workers = [Pure::NativeWorker]
56
+
57
+ name = parser.name.split("::").last
58
+ name = name.to_sym if RUBY_VERSION >= "1.9"
59
+ if CompilerWorker.constants.include?(name)
60
+ workers << CompilerWorker.const_get(name)
61
+ end
62
+
63
+ describe "[#{parser.name}]" do
64
+ before :each do
65
+ @previous_parser = Pure.parser
66
+ Pure.parser = parser
67
+ end
68
+ after :each do
69
+ Pure.parser = @previous_parser
70
+ end
71
+ workers.each { |worker|
72
+ describe "[#{worker}]" do
73
+ before :all do
74
+ @previous_worker = Pure.worker
75
+ worker.num_parallel = @previous_worker.num_parallel
76
+ Pure.worker = worker
77
+ end
78
+ after :all do
79
+ Pure.worker = @previous_worker
80
+ end
81
+ describe args.first, &block
82
+ end
83
+ }
84
+ end
85
+ }
86
+ else
87
+ describe__original(*args, &block)
88
+ end
89
+ end
90
+ end
91
+
92
+ #
93
+ # Prevent Ruby2Ruby's destruction of the sexp. In practice the
94
+ # compiler resides on another ruby interpreter, making the destruction
95
+ # harmless.
96
+ #
97
+ module Pure
98
+ module Compiler
99
+ class RubyParser
100
+ alias_method :compile_function__original, :compile_function
101
+ def compile_function(spec)
102
+ compile_function__original(Marshal.load(Marshal.dump(spec)))
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ describe "function defined with splat (*) argument via `def'" do
5
+ it "should raise error" do
6
+ lambda {
7
+ pure do
8
+ def f(a, b, *stuff)
9
+ stuff
10
+ end
11
+ end
12
+ }.should raise_error(
13
+ Pure::SplatError, %r!cannot use splat.*#{__FILE__}:8!
14
+ )
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ describe "with two defs on the same line" do
5
+ it "should raise error unless Pure::Parser::Internal is used" do
6
+ code = lambda {
7
+ pure do
8
+ def x ; end ; def y ; end
9
+ end
10
+ }
11
+ if Pure.parser.name == "Pure::Parser::Internal"
12
+ code.should_not raise_error
13
+ else
14
+ code.should raise_error(
15
+ Pure::ParseMethodError, "failed to parse `x' at #{__FILE__}:8"
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "Pure.worker" do
4
+ it "should return the current worker" do
5
+ Pure.worker.should_not == nil
6
+ end
7
+
8
+ it "should be changed with Pure.worker=" do
9
+ lambda {
10
+ mod = pure do
11
+ def f
12
+ end
13
+ end
14
+ }.should_not raise_error
15
+ previous = Pure.worker
16
+ Pure.worker = "junk"
17
+ begin
18
+ lambda {
19
+ mod = pure do
20
+ def f
21
+ end
22
+ end.compute.f
23
+ }.should raise_error
24
+ ensure
25
+ Pure.worker = previous
26
+ end
27
+ end
28
+
29
+ it "should have a default" do
30
+ Pure.worker = nil
31
+ Pure.worker.should_not == nil
32
+ end
33
+ end
@@ -1,35 +1,39 @@
1
- require 'pathname'
2
- require 'tempfile'
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
3
2
 
4
- here = Pathname(__FILE__).dirname
5
- require here + "common"
6
- root = here + ".."
7
- readme = root + "README.rdoc"
8
- lib = root + "lib"
3
+ require "jumpstart"
9
4
 
10
- describe readme do
11
- $LOAD_PATH.unshift root + "devel"
12
- require "jumpstart/ruby"
13
- ["Synopsis"].each { |section|
14
- describe section do
15
- it "should run as claimed" do
16
- contents = readme.read
17
-
18
- code = %{
19
- $LOAD_PATH.unshift "#{lib.expand_path}"
20
- require 'rubygems'
21
- } + contents.match(%r!== #{section}.*?\n(.*?)^\S!m)[1]
22
-
23
- expected = code.scan(%r!\# => (.*?)\n!).flatten.join("\n")
24
-
25
- Tempfile.open("pure-readme") { |file|
26
- file.puts code
27
- file.close
28
- result = `"#{Jumpstart::Ruby::EXECUTABLE}" "#{file.path}"`
29
- raise unless $?.exitstatus
30
- result.chomp.should == expected
31
- }
32
- end
33
- end
5
+ readme = "README.rdoc"
6
+
7
+ simple_sections = [
8
+ "Synopsis",
9
+ "Overrides",
10
+ "Delegates and Blocks",
11
+ "Combining Pure Modules",
12
+ "Restrictions",
13
+ "Default Number of Functions in Parallel",
14
+ ]
15
+
16
+ Jumpstart.doc_to_spec(readme, *simple_sections)
17
+
18
+ Jumpstart.doc_to_spec(readme, "Dynamic Names") { |expected, actual, index|
19
+ [expected, actual].each { |expr|
20
+ expr.should match(%r!\A[\d\s]+\Z!)
34
21
  }
35
- end
22
+ }
23
+
24
+ Jumpstart.doc_to_spec(readme, "Worker Plugins") { |expected, actual, index|
25
+ case index
26
+ when 0, 2
27
+ actual.should == expected
28
+ when 1
29
+ require 'ruby_parser'
30
+ trimmed_expected, trimmed_actual = [expected, actual].map { |expression|
31
+ result = eval(expression, TOPLEVEL_BINDING)
32
+ result[0].merge!(:file => nil, :line => nil)
33
+ result
34
+ }
35
+ trimmed_actual.should == trimmed_expected
36
+ else
37
+ raise
38
+ end
39
+ }
@@ -1,15 +1,16 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
2
 
3
- describe "splat (*) argument in pure function" do
4
- describe "with `def'" do
5
- it "should raise error" do
6
- lambda {
7
- pure do
8
- def f(a, b, *stuff)
9
- stuff
10
- end
11
- end
12
- }.should raise_error(Pure::PurePrivate::SplatError)
3
+ describe "splat" do
4
+ it "should be allowed outside of pure" do
5
+ Class.new do
6
+ def f(*args)
7
+ end
8
+ end
9
+
10
+ pure do
11
+ def g
12
+ 44
13
+ end
13
14
  end
14
15
  end
15
16
  end