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
@@ -1,36 +1,23 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
2
 
3
- describe "parse engine" do
4
- it "should be queryable" do
5
- pure do
6
- def f
3
+ describe "parser" do
4
+ describe "provided by user" do
5
+ it "should be accepted by pure" do
6
+ memo = nil
7
+ parser = Class.new do
8
+ define_method :extract do |*args|
9
+ memo = args
10
+ Hash.new
11
+ end
12
+ def name
13
+ "SampleParser"
14
+ end
15
+ end.new
16
+ mod = pure(parser) do
17
+ def f(x, y)
18
+ end
7
19
  end
8
- end
9
- lambda {
10
- Pure.parser
11
- }.should_not raise_error
12
- end
13
-
14
- it "should be swappable" do
15
- previous = Pure.parser
16
- begin
17
- Pure.parser = "ruby_parser"
18
- Pure.parser.should == "ruby_parser"
19
- ensure
20
- Pure.parser = previous
21
- end
22
- end
23
-
24
- it "should have a default unless Method#parameters available" do
25
- Pure.parser = nil
26
- pure do
27
- def f
28
- end
29
- end.compute(:f, 3)
30
- if Method.instance_methods.include?(:parameters)
31
- Pure.parser.should == nil
32
- else
33
- Pure.parser.should_not == nil
20
+ memo.should == [mod, :f, __FILE__, 17]
34
21
  end
35
22
  end
36
23
  end
@@ -0,0 +1,77 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ # factor out due to parsers changing
4
+ module PureCombineSpec
5
+ module_function
6
+
7
+ def create_mod_a
8
+ pure do
9
+ def area(width, height)
10
+ width*height
11
+ end
12
+
13
+ def border
14
+ 5
15
+ end
16
+ end
17
+ end
18
+
19
+ def create_mod_b
20
+ pure do
21
+ def width(border)
22
+ 20 + border
23
+ end
24
+
25
+ def height(border)
26
+ 30 + border
27
+ end
28
+ end
29
+ end
30
+
31
+ def create_combined
32
+ mod_a = create_mod_a
33
+ mod_b = create_mod_b
34
+ pure do
35
+ include mod_a
36
+ include mod_b
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "pure" do
42
+ describe "modules combined with other pure modules" do
43
+ max_threads = 5
44
+
45
+ it "should work with modules included into empty module" do
46
+ combined = PureCombineSpec.create_combined
47
+ (1..max_threads).each { |n|
48
+ combined.compute(n).area.should == (20 + 5)*(30 + 5)
49
+ }
50
+ end
51
+
52
+ it "should work with modules included into overriding module" do
53
+ combined = PureCombineSpec.create_combined
54
+ combined_override = pure do
55
+ include combined
56
+ def border
57
+ 99
58
+ end
59
+ end
60
+ (1..max_threads).each { |n|
61
+ combined_override.compute(n).area.should == (20 + 99)*(30 + 99)
62
+ }
63
+ end
64
+
65
+ it "should work with one module included into another" do
66
+ mod_a = PureCombineSpec.create_mod_a
67
+ mod_b = PureCombineSpec.create_mod_b
68
+ mod_a.module_eval do
69
+ include mod_b
70
+ end
71
+ (1..max_threads).each { |n|
72
+ mod_a.compute(n).area.should == (20 + 5)*(30 + 5)
73
+ }
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,186 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ describe "`def' definitions" do
5
+ it "should be parsed with 1 arg default" do
6
+ lambda {
7
+ pure do
8
+ def f(x = 99)
9
+ x
10
+ end
11
+ end
12
+ }.should raise_error(
13
+ Pure::DefaultArgumentError,
14
+ "cannot use default argument in pure function at #{__FILE__}:8"
15
+ )
16
+ end
17
+
18
+ it "should be parsed with non-paren 1 arg" do
19
+ pure do
20
+ def f x
21
+ x + 33
22
+ end
23
+ end.compute(3, :x => 44).f.should == 77
24
+ end
25
+
26
+ it "should be parsed with non-paren 1 arg splat" do
27
+ lambda {
28
+ pure do
29
+ def f *x
30
+ x + 33
31
+ end
32
+ end
33
+ }.should raise_error(Pure::SplatError)
34
+ end
35
+
36
+ it "should be parsed with non-paren 2 arg splat" do
37
+ lambda {
38
+ pure do
39
+ def f x, *y
40
+ x + 33
41
+ end
42
+ end
43
+ }.should raise_error(Pure::SplatError)
44
+ end
45
+
46
+ it "should be parsed with non-paren 2 args" do
47
+ pure do
48
+ def f x, y
49
+ x + y
50
+ end
51
+ end.compute(3, :x => 33, :y => 44).f.should == 77
52
+ end
53
+
54
+ it "should be parsed with 2 arg default" do
55
+ lambda {
56
+ pure do
57
+ def f(x, y = 99)
58
+ x + y
59
+ end
60
+ end
61
+ }.should raise_error(Pure::DefaultArgumentError)
62
+ end
63
+
64
+ it "should be parsed with non-paren 1 arg default" do
65
+ lambda {
66
+ pure do
67
+ def f x = 99
68
+ x + 44
69
+ end
70
+ end
71
+ }.should raise_error(Pure::DefaultArgumentError)
72
+ end
73
+
74
+ it "should be parsed with non-paren 2 arg 1 default" do
75
+ lambda {
76
+ pure do
77
+ def f x, y = 99
78
+ x + y
79
+ end
80
+ end
81
+ }.should raise_error(Pure::DefaultArgumentError)
82
+ end
83
+
84
+ it "should be parsed with non-paren 2 arg 2 default" do
85
+ lambda {
86
+ pure do
87
+ def f x = 77, y = 99
88
+ x + y
89
+ end
90
+ end
91
+ }.should raise_error(Pure::DefaultArgumentError)
92
+ end
93
+
94
+ it "should ignore &block" do
95
+ pure do
96
+ def f(&block)
97
+ 33
98
+ end
99
+ end.compute(4).f.should == 33
100
+ end
101
+
102
+ it "should ignore &block with 1 arg" do
103
+ pure do
104
+ def f(x, &block)
105
+ x + 44
106
+ end
107
+ end.compute(4, :x => 33).f.should == 77
108
+ end
109
+
110
+ it "should ignore &block with 2 arg" do
111
+ pure do
112
+ def f(x, y, &block)
113
+ x + 44
114
+ end
115
+ end.compute(4, :x => 33, :y => nil).f.should == 77
116
+ end
117
+
118
+ it "should ignore &block with 1 arg default" do
119
+ lambda {
120
+ pure do
121
+ def f(x = 11, &block)
122
+ x + 44
123
+ end
124
+ end
125
+ }.should raise_error(Pure::DefaultArgumentError)
126
+ end
127
+
128
+ it "should ignore no-paren &block" do
129
+ pure do
130
+ def f &block
131
+ 33
132
+ end
133
+ end.compute(4).f.should == 33
134
+ end
135
+
136
+ it "should ignore no-paren &block with 1 arg" do
137
+ pure do
138
+ def f x, &block
139
+ x + 44
140
+ end
141
+ end.compute(4, :x => 33).f.should == 77
142
+ end
143
+
144
+ it "should ignore no-paren &block with 2 arg" do
145
+ pure do
146
+ def f x, y, &block
147
+ x + 44
148
+ end
149
+ end.compute(4, :x => 33, :y => nil).f.should == 77
150
+ end
151
+
152
+ it "should ignore no-paren &block with 1 arg default" do
153
+ lambda {
154
+ pure do
155
+ def f x = 11, &block
156
+ x + 44
157
+ end
158
+ end
159
+ }.should raise_error(Pure::DefaultArgumentError)
160
+ end
161
+
162
+ it "should have fun_name and arg_names" do
163
+ pure do
164
+ def f(x, y)
165
+ [fun_name, arg_names, x + y]
166
+ end
167
+ end.compute(:x => 11, :y => 22).f.should == [:f, [:x, :y], 33]
168
+ end
169
+
170
+ it "should have fun_name and arg_names, given 1 arg" do
171
+ pure do
172
+ def f(x)
173
+ [fun_name, arg_names, x]
174
+ end
175
+ end.compute(:x => 11).f.should == [:f, [:x], 11]
176
+ end
177
+
178
+ it "should have fun_name and arg_names, given no args" do
179
+ pure do
180
+ def f
181
+ [fun_name, arg_names]
182
+ end
183
+ end.compute.f.should == [:f, []]
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ it "should raise error when define_method called" do
5
+ lambda {
6
+ pure do
7
+ define_method :area do |width, height|
8
+ width*height
9
+ end
10
+
11
+ def width
12
+ 5
13
+ end
14
+
15
+ def height
16
+ 7
17
+ end
18
+ end.compute :area, 3
19
+ }.should raise_error(
20
+ Pure::DefineMethodError,
21
+ %r!cannot use define_method.* at #{__FILE__}:7!
22
+ )
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ describe "pure" do
4
+ describe "defined inside eval" do
5
+ it "should raise an error" do
6
+ lambda {
7
+ code = %{
8
+ pure do
9
+ def f
10
+ 33
11
+ end
12
+ end
13
+ }
14
+ eval(code)
15
+ }.should raise_error(Pure::EvalError, %r!#{__FILE__}:14!)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,243 @@
1
+ require File.dirname(__FILE__) + '/pure_spec_base'
2
+
3
+ require 'jumpstart'
4
+
5
+ describe "pure" do
6
+ describe "`fun' definitions" do
7
+ it "should work with symbols" do
8
+ pure do
9
+ fun :area => [:width, :height] do |w, h|
10
+ w*h
11
+ end
12
+
13
+ fun :width => [:border] do |b|
14
+ 20 + b
15
+ end
16
+
17
+ fun :height => :border do |b|
18
+ 30 + b
19
+ end
20
+
21
+ fun :border do
22
+ 5
23
+ end
24
+ end.compute(4).area.should == (20 + 5)*(30 + 5)
25
+ end
26
+
27
+ it "should work with symbols and parens" do
28
+ pure do
29
+ fun(:area => [:width, :height]) do |w, h|
30
+ w*h
31
+ end
32
+
33
+ fun(:width => [:border]) do |b|
34
+ 20 + b
35
+ end
36
+
37
+ fun(:height => :border) do |b|
38
+ 30 + b
39
+ end
40
+
41
+ fun(:border) do
42
+ 5
43
+ end
44
+ end.compute(4).area.should == (20 + 5)*(30 + 5)
45
+ end
46
+
47
+ it "should work with mixed symbols and strings" do
48
+ pure do
49
+ fun :area => [:width, "height"] do |w, h|
50
+ w*h
51
+ end
52
+
53
+ fun "width" => [:border] do |b|
54
+ 20 + b
55
+ end
56
+
57
+ fun :height => "border" do |b|
58
+ 30 + b
59
+ end
60
+
61
+ fun :border do
62
+ 5
63
+ end
64
+ end.compute(4).area.should == (20 + 5)*(30 + 5)
65
+ end
66
+
67
+ it "should work with `def' definitions" do
68
+ pure do
69
+ fun :width do
70
+ 33
71
+ end
72
+
73
+ def height
74
+ 44
75
+ end
76
+
77
+ fun :area => [:width, :height] do |w, h|
78
+ w*h
79
+ end
80
+ end.compute(3).area.should == 33*44
81
+ end
82
+
83
+ it "should be overwritten by later `def' definitions" do
84
+ Jumpstart::Ruby.no_warnings {
85
+ pure do
86
+ fun :f do
87
+ 44
88
+ end
89
+
90
+ def f
91
+ 33
92
+ end
93
+ end.compute(10).f.should == 33
94
+ }
95
+ end
96
+
97
+ it "should overwrite earlier `def' definitions" do
98
+ Jumpstart::Ruby.no_warnings {
99
+ pure do
100
+ def f
101
+ 33
102
+ end
103
+
104
+ fun :f do
105
+ 44
106
+ end
107
+ end.compute(10).f.should == 44
108
+ }
109
+ end
110
+
111
+ it "should support splat in block args" do
112
+ pure do
113
+ fun :area => [:width, :height] do |*a|
114
+ a[0]*a[1]
115
+ end
116
+
117
+ def width
118
+ 3
119
+ end
120
+
121
+ def height
122
+ 4
123
+ end
124
+ end.compute(3).area.should == 12
125
+ end
126
+
127
+ it "should support splat with single-element array" do
128
+ pure do
129
+ name = [:f]
130
+ fun(*name) do
131
+ 33
132
+ end
133
+ end.compute(3).f.should == 33
134
+ end
135
+
136
+ it "should not preclude `def' definitions called `fun'" do
137
+ pure do
138
+ def misery(fun)
139
+ fun**2
140
+ end
141
+
142
+ def fun(a, b)
143
+ a + b
144
+ end
145
+
146
+ def a
147
+ 3
148
+ end
149
+
150
+ def b
151
+ 5
152
+ end
153
+ end.compute(3).misery.should == 64
154
+ end
155
+
156
+ it "should raise error when given hash of size != 1" do
157
+ lambda {
158
+ pure do
159
+ fun :x => 1, :y => 2 do
160
+ end
161
+ end
162
+ }.should raise_error(ArgumentError)
163
+ end
164
+
165
+ it "should raise error given more than 1 argument" do
166
+ lambda {
167
+ pure do
168
+ fun :x, :y do
169
+ end
170
+ end
171
+ }.should raise_error(ArgumentError)
172
+ end
173
+
174
+ it "should raise error with &block unless Pure::Parser::Internal is used" do
175
+ code = lambda {
176
+ pure do
177
+ fun :f, &lambda { 33 }
178
+ end.compute(4).f.should == 33
179
+ }
180
+ if Pure.parser.name == "Pure::Parser::Internal"
181
+ code.should_not raise_error
182
+ else
183
+ code.should raise_error(Pure::ParseError)
184
+ end
185
+
186
+ code = lambda {
187
+ pure do
188
+ t = lambda { 33 }
189
+ fun :f, &t
190
+ end.compute(4).f.should == 33
191
+ }
192
+ if Pure.parser.name == "Pure::Parser::Internal"
193
+ code.should_not raise_error
194
+ else
195
+ code.should raise_error(Pure::ParseError)
196
+ end
197
+ end
198
+
199
+ it "should allow function names containing any characters" do
200
+ %w[- / ? : ; . ! [ ] ( )].each { |char|
201
+ pure do
202
+ fun "f#{char}f" do
203
+ 33
204
+ end
205
+ end.compute[:"f#{char}f"].should == 33
206
+ }
207
+ end
208
+
209
+ it "should have fun_name and arg_names, given multiple args" do
210
+ pure do
211
+ fun :f => [:x, :y] do |x, y|
212
+ [fun_name, arg_names, x + y]
213
+ end
214
+ end.compute(:x => 11, :y => 22).f.should == [:f, [:x, :y], 33]
215
+ end
216
+
217
+ it "should have fun_name and fun_args, given 1 arg" do
218
+ pure do
219
+ fun :f => :x do |x|
220
+ [fun_name, arg_names, x]
221
+ end
222
+ end.compute(:x => 11).f.should == [:f, [:x], 11]
223
+ end
224
+
225
+ it "should have fun_name and fun_args, given no args" do
226
+ pure do
227
+ fun :f do
228
+ [fun_name, arg_names]
229
+ end
230
+ end.compute.f.should == [:f, []]
231
+ end
232
+
233
+ it "should not see internals of the compiler" do
234
+ lambda {
235
+ pure do
236
+ fun :f do
237
+ spec
238
+ end
239
+ end.compute.f
240
+ }.should raise_error(NameError)
241
+ end
242
+ end
243
+ end