haskell 0.2.3 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f7af12f3fa2dceabef05ccb39a3f7853c69ab0a
4
- data.tar.gz: 93808939d0d3e5a156f03e826a6a79bdbb548b59
3
+ metadata.gz: ac0c087788b1e471523aed86d8dfd0c42be2503d
4
+ data.tar.gz: 610eff264b8bdc1903ea519e857a5346f461aad6
5
5
  SHA512:
6
- metadata.gz: e1e2484689e7c753b2910b936391a3bcea009a48832855b8999ee2a74092215d50fb0747533e61fce8cc7895087539112ba38705f8d2336a03f01c16b2ff62c0
7
- data.tar.gz: 00ffb2cb3a0786ca43a3701b396214cc29465573125bf949af52b210c9081d90338f48635924a23639f3e18c184bb6a0650ff7c05058e0c888a44b24c1a28c88
6
+ metadata.gz: 788e9b367f36ec0420f44fa89166768073332e8748aab5acd65f9c1796e1953367a2e9ed9bc5b738e0fdf53f6eb329237205e6a6dd819851f437b92264f7ccd5
7
+ data.tar.gz: ae3aa09d9fd3af02d5361bccc45f33d27f6e153b5f9a2a2810693493bd18c5fc8a33f4d35ccd5e19f6be4ff179346376f9533753fad70665614055f42081f174
data/README.md CHANGED
@@ -1,107 +1,17 @@
1
- # Ruby with Type.
2
-
3
- Matz has mentioned Ruby3.0 with static type at some confluences. But almost all rubyists(include me) are not sure how typed Ruby is.
4
-
5
- But it's worth thinking more. This gem is kind of trial without so much side-effect.
1
+ # Haskell On Ruby
6
2
 
7
3
  ```rb
8
4
  require 'haskell'
9
-
10
- # ex1
11
- class MyClass
12
- def sum(x, y)
13
- x + y
14
- end
15
- typesig sum: [Numeric, Numeric => Numeric]
16
-
17
- def wrong_sum(x, y)
18
- 'string'
19
- end
20
- typesig wrong_sum: [Numeric, Numeric => Numeric]
5
+ Haskell.compile %{
6
+ add :: Integer -> Integer -> Integer
7
+ add x y = x + y
8
+ result = add 1 2
9
+ }
10
+
11
+ while Haskell.compiling?
12
+ ...
21
13
  end
22
14
 
23
- MyClass.new.sum(1, 2)
15
+ p Haskell.execute
24
16
  #=> 3
25
-
26
- MyClass.new.sum(1, 'string')
27
- #=> ArgumentError: Wrong type of argument, type of "str" should be Numeric
28
-
29
- MyClass.new.wrong_sum(1, 2)
30
- #=> TypeError: Expected wrong_sum to return Numeric but got "str" instead
31
-
32
-
33
- # ex2
34
- class People
35
- type People >= Any, def marry(people)
36
- # Your Ruby code as usual
37
- end
38
- end
39
- typesig marry: [People => Any]
40
-
41
- People.new.marry(People.new)
42
- #=> no error
43
-
44
- People.new.marry('non people')
45
- #=> ArgumentError: Wrong type of argument, type of "non people" should be People
46
17
  ```
47
-
48
- ## Feature
49
- ### Typed method can coexist with non-typed method
50
-
51
- ```ruby
52
- # It's totally OK!!
53
- class MyClass
54
- def sum(x, y)
55
- x + y
56
- end
57
- typesig sum: [Numeric, Numeric => Numeric]
58
-
59
- def sum_without_type(x, y)
60
- 'string'
61
- end
62
- end
63
- ```
64
-
65
- ### Duck typing
66
-
67
- ```ruby
68
-
69
- class MyClass
70
- def foo(any_obj)
71
- 1
72
- end
73
- typesig sum: [Any => Numeric]
74
- end
75
-
76
- # It's totally OK!!
77
- MyClass.new.foo(1)
78
- # It's totally OK!!
79
- MyClass.new.foo('str')
80
- ```
81
-
82
- ## Installation
83
-
84
- gem install haskell or add gem 'haskell' to your Gemfile.
85
-
86
- This gem requires Ruby 2.0.0+.
87
-
88
- ### Contributing
89
-
90
- Fork it ( https://github.com/[my-github-username]/haskell/fork )
91
-
92
- Create your feature branch (`git checkout -b my-new-feature`)
93
-
94
- $ bundle install --path vendor/bundle
95
-
96
- Commit your changes (`git commit -am 'Add some feature'`)
97
-
98
- $ bundle exec rake test
99
-
100
- > 5 runs, 39 assertions, 0 failures, 0 errors, 0 skips
101
-
102
- Push to the branch (`git push origin my-new-feature`)
103
-
104
- Create a new Pull Request
105
-
106
- ## Credits
107
- [@chancancode](https://github.com/chancancode) first brought this to my attention. I've stolen some idea from him.
data/lib/haskell.rb CHANGED
@@ -1,48 +1,73 @@
1
- # Builtin Contracts
2
- class Any; end
3
- module Boolean; end
4
- TrueClass.send(:include, Boolean)
5
- FalseClass.send(:include, Boolean)
6
-
7
- class Module
8
- private
9
- def __haskell__
10
- prepend (@__haskell__ = Module.new) unless @__haskell__
11
- @__haskell__
12
- end
1
+ module Haskell
2
+ # TODO:
3
+ class HaskellCompileError < StandardError; end
13
4
 
14
- def typesig(hash)
15
- meth = hash.keys.first
16
- *arg_types, type_pair = hash.values.first
5
+ class << self
6
+ def invoke_sandbox!
7
+ file_path = File.expand_path('../', __FILE__)
8
+ $sandbox_path = "#{file_path}/haskell_executing_sandbox"
9
+ FileUtils.mkdir($sandbox_path) unless Dir.exist?($sandbox_path)
10
+ end
17
11
 
18
- __haskell__.send(:define_method, meth) do |*args, &block|
19
- ::Haskell.assert_arg_type(meth, args, arg_types << type_pair.keys.first)
20
- rtn = super(*args, &block)
21
- ::Haskell.assert_trn_type(meth, rtn, type_pair.values.first)
22
- rtn
12
+ def revoke_sandbox!
13
+ FileUtils.rm_rf($sandbox_path)
23
14
  end
24
- self
25
- end
26
- end
27
15
 
28
- module Haskell
29
- class << self
30
- def assert_arg_type(meth, args, klasses)
31
- args.each_with_index do |arg, i|
32
- if wrong_type?(arg, klasses[i])
33
- raise ArgumentError, "Wrong type of argument, type of #{arg.inspect} should be #{klasses[i]}"
16
+ def compile(hs_code)
17
+ FileUtils.touch("#{$sandbox_path}/COMPILING")
18
+ #TODO: need inform user prefer message
19
+ Thread.abort_on_exception = true
20
+ Thread.new do
21
+ begin
22
+ executable_code = executable_code(hs_code)
23
+ puts_notation(executable_code)
24
+ File.write("#{$sandbox_path}/tmp.hs", executable_code)
25
+ Kernel.system("ghc #{$sandbox_path}/tmp.hs")
26
+ raise HaskellCompileError unless compiled?
27
+ ensure
28
+ FileUtils.rm("#{$sandbox_path}/COMPILING")
34
29
  end
35
30
  end
31
+ rescue
32
+ raise "Something wrong...https://github.com/Azabuhs/Ruby/issues"
36
33
  end
37
34
 
38
- def assert_trn_type(meth, rtn, klass)
39
- if wrong_type?(rtn, klass)
40
- raise TypeError, "Expected #{meth} to return #{klass} but got #{rtn.inspect} instead"
41
- end
35
+ def compiling?
36
+ File.exist?("#{$sandbox_path}/COMPILING")
42
37
  end
43
38
 
44
- def wrong_type?(obj, klass)
45
- !(obj.is_a?(klass) || klass == Any)
39
+ def compiled?
40
+ File.exist?("#{$sandbox_path}/tmp")
41
+ end
42
+
43
+ def execute
44
+ `#{$sandbox_path}/tmp`.gsub(/\n\z/, '')
45
+ end
46
+
47
+ private
48
+
49
+ def executable_code(hs_code)
50
+ # TODO: other white space
51
+ hs_code =~/\A\n( *)/
52
+ hs_code.gsub!(/\n#{$1}/, "\n")
53
+ <<-HASKELL_CODE
54
+ module Main where
55
+ #{hs_code}
56
+ main = do putStrLn $ show result
57
+ HASKELL_CODE
58
+ end
59
+
60
+ def puts_notation(executable_code)
61
+ puts <<-NOTATION
62
+ # GHC will compile below code
63
+ ###############################
64
+ NOTATION
65
+
66
+ puts '# ' + executable_code.gsub("\n", "\n# ")
67
+
68
+ puts <<-NOTATION
69
+ ###############################
70
+ NOTATION
46
71
  end
47
72
  end
48
73
  end
@@ -1,3 +1,3 @@
1
1
  module Haskell
2
- VERSION = "0.2.3"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,46 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestHaskell < MiniTest::Unit::TestCase
4
+ def test_main
5
+ assert_equal_execute('3') {"
6
+ add :: Integer -> Integer -> Integer
7
+ add x y = x + y
8
+ result = add 1 2
9
+ "}
10
+
11
+ assert_equal_execute('[3.1415927,4.0]') {"
12
+ data Point = Pt Float Float deriving (Show)
13
+ data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
14
+ surface :: Shape -> Float
15
+ surface (Circle _ r) | r > 0 = pi * r ^ 2
16
+ | otherwise = 0
17
+
18
+ surface (Rectangle (Pt x1 y1) (Pt x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
19
+
20
+ result = [surface (Circle (Pt 0 0) 1), surface (Rectangle (Pt 2 3) (Pt 4 5))]
21
+ "}
22
+
23
+ assert_raise_compile_error {"
24
+ Error
25
+ "}
26
+ end
27
+
28
+ private
29
+ def assert_equal_execute(str, &block)
30
+ Haskell.invoke_sandbox!
31
+ Haskell.compile(block.call)
32
+ nil while Haskell.compiling?
33
+ assert_equal str, Haskell.execute
34
+ Haskell.revoke_sandbox!
35
+ end
36
+
37
+ def assert_raise_compile_error(&block)
38
+ Haskell.invoke_sandbox!
39
+ Haskell.compile(block.call)
40
+ nil while Haskell.compiling?
41
+ # TODO: more prefer test
42
+ rescue Haskell::HaskellCompileError
43
+ assert(true)
44
+ Haskell.revoke_sandbox!
45
+ end
46
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haskell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - gogotanaka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-07 00:00:00.000000000 Z
11
+ date: 2014-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -85,7 +85,7 @@ files:
85
85
  - lib/haskell/version.rb
86
86
  - rubype.gemspec
87
87
  - test/minitest_helper.rb
88
- - test/test_rubype.rb
88
+ - test/test_haskell.rb
89
89
  homepage: http://gogotanaka.me/
90
90
  licenses:
91
91
  - MIT
@@ -112,4 +112,4 @@ specification_version: 4
112
112
  summary: Ruby with type.
113
113
  test_files:
114
114
  - test/minitest_helper.rb
115
- - test/test_rubype.rb
115
+ - test/test_haskell.rb
data/test/test_rubype.rb DELETED
@@ -1,107 +0,0 @@
1
- require 'minitest_helper'
2
- class TypePair
3
- def to_s
4
- "#{last_arg_type} => #{rtn_type}"
5
- end
6
- end
7
- class TestHaskell < MiniTest::Unit::TestCase
8
- def setup
9
- @string = 'str'
10
- @numeric = 1
11
- @symbol = :test
12
- @array = [1, 2, 3]
13
- @hash = { test: :hash }
14
- end
15
-
16
- def test_correct_type
17
- assert_correct_type [Numeric => Numeric], [@numeric], @numeric
18
- assert_correct_type [Numeric => Array ], [@numeric], @array
19
- assert_correct_type [Numeric => String ], [@numeric], @string
20
- assert_correct_type [Numeric => Hash ], [@numeric], @hash
21
- assert_correct_type [Numeric => Symbol ], [@numeric], @symbol
22
- assert_correct_type [Numeric => Boolean], [@numeric], true
23
- assert_correct_type [Numeric => Boolean], [@numeric], false
24
-
25
- assert_correct_type [Boolean, Numeric => Numeric], [true, @numeric], @numeric
26
- assert_correct_type [Boolean, Array => Array ], [true, @array ], @array
27
- assert_correct_type [Boolean, String => String ], [true, @string ], @string
28
- assert_correct_type [Boolean, Hash => Hash ], [true, @hash ], @hash
29
- assert_correct_type [Boolean, Symbol => Symbol ], [true, @symbol ], @symbol
30
- end
31
-
32
- def test_wrong_return_type
33
- assert_wrong_rtn [Numeric => Numeric], [@numeric], @array
34
- assert_wrong_rtn [Numeric => Numeric], [@numeric], @string
35
- assert_wrong_rtn [Numeric => Numeric], [@numeric], @hash
36
- assert_wrong_rtn [Numeric => Numeric], [@numeric], @symbol
37
- assert_wrong_rtn [Numeric => Numeric], [@numeric], true
38
-
39
- assert_wrong_rtn [Numeric, Numeric => Numeric], [@numeric, @numeric], @array
40
- assert_wrong_rtn [Numeric, Numeric => Numeric], [@numeric, @numeric], @string
41
- assert_wrong_rtn [Numeric, Numeric => Numeric], [@numeric, @numeric], @hash
42
- assert_wrong_rtn [Numeric, Numeric => Numeric], [@numeric, @numeric], @symbol
43
- assert_wrong_rtn [Numeric, Numeric => Numeric], [@numeric, @numeric], true
44
- end
45
-
46
- def test_wrong_args_type
47
- assert_wrong_arg [Numeric => Numeric], [@array ], @numeric
48
- assert_wrong_arg [Numeric => Numeric], [@string], @numeric
49
- assert_wrong_arg [Numeric => Numeric], [@hash ], @numeric
50
- assert_wrong_arg [Numeric => Numeric], [@symbol], @numeric
51
- assert_wrong_arg [Numeric => Numeric], [true ], @numeric
52
-
53
- assert_wrong_arg [Numeric, Numeric => Numeric], [@numeric, @array ], @numeric
54
- assert_wrong_arg [Numeric, Numeric => Numeric], [@numeric, @string], @numeric
55
- assert_wrong_arg [Numeric, Numeric => Numeric], [@numeric, @hash ], @numeric
56
- assert_wrong_arg [Numeric, Numeric => Numeric], [@numeric, @symbol], @numeric
57
- assert_wrong_arg [Numeric, Numeric => Numeric], [@numeric, true ], @numeric
58
- end
59
-
60
- def test_any
61
- assert_correct_type [Any => Any], [@array ], @numeric
62
- assert_correct_type [Any => Any], [@string], @numeric
63
- assert_correct_type [Any => Any], [@hash ], @numeric
64
- assert_correct_type [Any => Any], [@symbol], @numeric
65
-
66
- assert_correct_type [Any, Any => Any], [@numeric, @array ], @numeric
67
- assert_correct_type [Any, Any => Any], [@numeric, @string], @numeric
68
- assert_correct_type [Any, Any => Any], [@numeric, @hash ], @numeric
69
- assert_correct_type [Any, Any => Any], [@numeric, @symbol], @numeric
70
- end
71
-
72
- private
73
- def assert_equal_to_s(str, val)
74
- assert_equal str, val.to_s
75
- end
76
-
77
- def assert_correct_type(type_list, args, val)
78
- assert_equal val, define_test_method(type_list, args, val).call(*args)
79
- end
80
-
81
- def assert_wrong_arg(type_list, args, val)
82
- assert_raises(ArgumentError) { define_test_method(type_list, args, val).call(*args) }
83
- end
84
-
85
- def assert_wrong_rtn(type_list, args, val)
86
- assert_raises(TypeError) { define_test_method(type_list, args, val).call(*args) }
87
- end
88
-
89
- def define_test_method(type_list, args, val)
90
- klass = Class.new.class_eval <<-RUBY_CODE
91
- def call(#{arg_literal(args.count)})
92
- #{obj_literal(val)}
93
- end
94
- typesig call: #{obj_literal(type_list)}
95
- RUBY_CODE
96
-
97
- klass.new
98
- end
99
-
100
- def obj_literal(obj)
101
- "ObjectSpace._id2ref(#{obj.__id__})"
102
- end
103
-
104
- def arg_literal(count)
105
- ('a'..'z').to_a[0..count-1].join(',')
106
- end
107
- end