pure 0.1.0 → 0.2.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 (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