h8 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/h8/ruby_gate.cpp CHANGED
@@ -14,7 +14,6 @@ static void* unblock_caller(void *param) {
14
14
  }
15
15
 
16
16
  static void with_gvl(RubyGate *gate, const std::function<void(void)> &block) {
17
- // v8::Unlocker unlock(gate->isolate());
18
17
  H8 *h8 = gate->getH8();
19
18
  if (h8->isGvlReleased()) {
20
19
  h8->setGvlReleased(false);
data/ext/h8/ruby_gate.h CHANGED
@@ -41,9 +41,7 @@ public:
41
41
  }
42
42
 
43
43
  virtual void free() {
44
- AllocatedResource::free();
45
- persistent().ClearWeak();
46
- persistent().Reset();
44
+ // printf("RG::FREE(%p)\n", this);
47
45
  delete this;
48
46
  }
49
47
 
@@ -52,6 +50,10 @@ public:
52
50
  }
53
51
 
54
52
  virtual ~RubyGate() {
53
+ // puts("~RG()");
54
+ persistent().ClearWeak();
55
+ persistent().Reset();
56
+ // The rest is done by the base classes
55
57
  }
56
58
 
57
59
  Isolate* isolate() const noexcept {
data/lib/h8/coffee.rb CHANGED
@@ -36,13 +36,15 @@ module H8
36
36
  # Create compiler instance.
37
37
  def initialize
38
38
  @context = H8::Context.new
39
- @context.eval open(File.join(File.dirname(File.expand_path(__FILE__)),'/coffee-script.js'), 'r').read
39
+ @context.eval read_script 'coffee-script.js'
40
+ eval read_script('globals.coffee')
40
41
  end
41
42
 
42
43
  # compile coffeescript source and return compiled javascript
43
- def compile src, **kwargs
44
+ def compile src, file_name: nil, **kwargs
44
45
  @context[:cs] = src
45
- res = @context.eval('CoffeeScript.compile(cs)')
46
+ @context[:filename] = file_name
47
+ res = @context.eval('CoffeeScript.compile(cs,{filename: filename})')
46
48
  @context[:cs] = nil # Sources can be big...
47
49
  res
48
50
  end
@@ -52,6 +54,20 @@ module H8
52
54
  def eval src, **kwargs
53
55
  @context.eval compile(src), **kwargs
54
56
  end
57
+
58
+ # Provide context with CoffeeScrip compiler loaded
59
+ def context
60
+ @context
61
+ end
62
+
63
+ private
64
+
65
+ @@base = File.expand_path File.join(File.dirname(__FILE__), '../scripts')
66
+ @@cache = {}
67
+
68
+ def read_script name
69
+ @@cache[name] ||= open(File.join(@@base, name), 'r').read
70
+ end
55
71
  end
56
72
 
57
73
 
data/lib/h8/command.rb ADDED
@@ -0,0 +1,128 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'pargser'
3
+ require 'ostruct'
4
+ require 'h8'
5
+
6
+ module H8
7
+
8
+ class Command
9
+
10
+ def initialize *args, out: STDOUT, err: STDERR
11
+ @out = out
12
+ @err = err
13
+
14
+ run *args if args.length > 0
15
+ end
16
+
17
+ def run *args
18
+ count = 0
19
+
20
+ @parser = Pargser.new(args)
21
+
22
+ @parser.key('-e', default: false, doc: 'inline coffee code to execute') { |script|
23
+ if script
24
+ @file = '-e'
25
+ context.coffee (@script=script)
26
+ count += 1
27
+ end
28
+ }
29
+ .key('-x', default: nil, doc: 'inline js code to execute') { |script|
30
+ if script
31
+ @file = '-e'
32
+ context.eval (@script=script)
33
+ count += 1
34
+ end
35
+ }
36
+
37
+ @parser.parse { |file|
38
+ count += 1
39
+ @script = open(file, 'r').read
40
+ file.downcase.end_with?('.coffee') and @script = H8::Coffee.compile(@script)
41
+ @file = file
42
+ context.eval @script
43
+ }
44
+
45
+ count > 0 or raise 'Must provide at least one file'
46
+ end
47
+
48
+ def context
49
+ @context ||= begin
50
+ cxt = H8::Context.new
51
+ console = Console.new out: @out, err: @err
52
+ cxt[:console] = console
53
+ print = -> (*args) { console.debug *args }
54
+ cxt[:print] = print
55
+ cxt[:puts] = print
56
+ cxt[:open] = -> (name, mode='r', block=nil) { Stream.new(name, mode, block) }
57
+ cxt['__FILE__'] = @file ? @file.to_s : '<inline>'
58
+ cxt[:File] = FileProxy.new
59
+ cxt
60
+ end
61
+ end
62
+
63
+ def usage
64
+ "\nh8 #{H8::VERSION} CLI inteface\n\n" +
65
+ "Usage: h8 <file.js/file.coffe>\n\n" +
66
+ @parser.keys_doc
67
+ end
68
+
69
+ class FileProxy
70
+ def dirname str
71
+ File.dirname str
72
+ end
73
+
74
+ def extname str
75
+ File.extname str
76
+ end
77
+
78
+ def basename str
79
+ File.basename str
80
+ end
81
+
82
+ def expand_path str
83
+ File.expand_path str
84
+ end
85
+
86
+ end
87
+
88
+ class Stream
89
+ def initialize name, mode, block=nil
90
+ @file = open(name, mode)
91
+ if block
92
+ block.call self
93
+ @file.close
94
+ end
95
+ end
96
+
97
+ def read(count=nil)
98
+ if count
99
+ @file.read(count)
100
+ else
101
+ @file.read
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ class Console
108
+ def initialize out: STDOUT, err: STDERR
109
+ @out, @err = out, err
110
+ end
111
+
112
+ def debug *args
113
+ @out.puts args.join(' ')
114
+ end
115
+
116
+ def log *args
117
+ debug *args
118
+ end
119
+
120
+ def error *args
121
+ @err.puts args.join(' ')
122
+ end
123
+ end
124
+
125
+
126
+ end
127
+
128
+ end
data/lib/h8/context.rb CHANGED
@@ -25,7 +25,7 @@ module H8
25
25
  # * ruby Class - creating a javascript constructor function that creates ruby
26
26
  # class instance (any arguments) and gates it to use with js.
27
27
  def []= name, value
28
- set_all name => value
28
+ set_all name.to_sym => value
29
29
  end
30
30
 
31
31
  # Execute a given script on the current context with optionally limited execution time.
@@ -37,16 +37,25 @@ module H8
37
37
  #
38
38
  # @return [Value] wrapped object returned by the script
39
39
  # @raise [H8::TimeoutError] if the timeout was set and expired
40
- def eval script, max_time: 0, timeout: 0
40
+ def eval script, max_time: 0, timeout: 0, file_name: nil
41
41
  timeout = max_time * 1000 if max_time > 0
42
42
  yield(self) if block_given?
43
- _eval script, timeout.to_i
43
+ _eval script, timeout.to_i, file_name
44
44
  end
45
45
 
46
+ # Compile and execute coffeescript, taking same arguments as #eval.
47
+ #
48
+ # If you need to execute same script more than once consider first H8::Coffee.compile
49
+ # and cache compiled script.
50
+ def coffee script, ** kwargs
51
+ eval Coffee.compile script, **kwargs
52
+ end
53
+
54
+
46
55
  # Execute script in a new context with optionally set vars. @see H8#set_all
47
56
  # @return [Value] wrapped object returned by the script
48
- def self.eval script, **kwargs
49
- Context.new(** kwargs).eval script
57
+ def self.eval script, file_name: nil, **kwargs
58
+ Context.new(** kwargs).eval script, file_name: file_name
50
59
  end
51
60
 
52
61
  # Secure gate for JS to securely access ruby class properties (methods with no args)
@@ -111,20 +120,4 @@ module H8
111
120
  end
112
121
  end
113
122
 
114
- # class RacerContext < Context
115
- # protected
116
- # def set_var name, value
117
- # if value.is_a?(Proc)
118
- # n1 = "___compat_#{name}"
119
- # _eval "function #{name}() { return #{n1}( this, arguments); }", 0
120
- # super n1, -> (this, arguments) {
121
- # args = [this] + H8::arguments_to_a(arguments)
122
- # value.call *args
123
- # }
124
- # else
125
- # super name, value
126
- # end
127
- # end
128
- # end
129
-
130
123
  end
data/lib/h8/errors.rb CHANGED
@@ -8,26 +8,27 @@ module H8
8
8
  # The general error caused by the script execution, e.g. uncaught javascript exceptinos and like.
9
9
  # Check #message to see the cause.
10
10
  class JsError < Error
11
- # Error message
12
- attr :message
13
11
 
14
12
  # Javascript Error object. May be nil
15
13
  attr :javascript_error
16
14
 
17
- def to_s
18
- message
19
- end
20
-
21
15
  # Error name
22
16
  def name
23
- @javascript_error.name ? @javascript_error.name : message
17
+ @javascript_error.name ? @javascript_error.name : @message
24
18
  end
25
19
 
26
20
  # String that represents stack trace if any as multiline string (\n separated)
27
21
  def javascript_backtrace
28
- @javascript_error ? @javascript_error.stack : message
22
+ @javascript_error ? @javascript_error.stack : @message
29
23
  end
30
24
 
25
+ def to_s
26
+ javascript_backtrace
27
+ end
28
+
29
+ def message
30
+ to_s
31
+ end
31
32
  end
32
33
 
33
34
  # Script execution is timed out (see H8::Context#eval timeout parameter)
data/lib/h8/pargser.rb ADDED
@@ -0,0 +1,133 @@
1
+ require 'set'
2
+
3
+ module H8
4
+ class Pargser
5
+
6
+ class Error < ArgumentError; end
7
+
8
+ # Create parser instance with a list of arguments. Otherwise, arguments can
9
+ # be passed to #parse call.
10
+ #
11
+ # @param [Array] args arguments
12
+ def initialize args=[]
13
+ @args = args
14
+ @keys = {}
15
+ @required = Set.new
16
+ @docs = []
17
+ end
18
+
19
+ # Register key handler.
20
+ # When #parse handler blocks will be called in order of appearance in
21
+ # arguments array
22
+ #
23
+ #
24
+ # @param [String] name key name
25
+ #
26
+ # @param [Array(String)] aliases for the key
27
+ #
28
+ # @param [Boolean] :needs_value if set then the parser wants a value argument after the
29
+ # key which will be passed to block as an argument. if default param is not set and
30
+ # the key will not be detected, Pargser::Error will be raised
31
+ #
32
+ # @param [String] :default value. if set, needs_value parameter can be omitted - the handler
33
+ # block will be passed either with this value or with one specified in args.
34
+ #
35
+ # @param [String] :doc optional documentation string that will be used in #keys_doc
36
+ #
37
+ # @yield block if the key is found with optional value argument
38
+ #
39
+ def key name, *aliases, needs_value: false, doc: nil, **kwargs, &block
40
+ k = name.to_s
41
+
42
+ default_set = false
43
+ default = nil
44
+ if kwargs.include?(:default)
45
+ default = kwargs[:default]
46
+ needs_value = true
47
+ default_set = true
48
+ end
49
+
50
+ @keys.include?(k) and raise Error, "Duplicate key registration #{k}"
51
+ data = @keys[k] = OpenStruct.new required: false,
52
+ needs_value: needs_value,
53
+ block: block,
54
+ doc: doc,
55
+ key: k,
56
+ aliases: aliases,
57
+ default: default,
58
+ default_set: default_set
59
+ @docs << data
60
+ aliases.each { |a| @keys[a.to_s] = data }
61
+ @required.add(data) if needs_value
62
+ self
63
+ end
64
+
65
+ # Process command line and call key handlers in the order of
66
+ # appearance. Then call handlers that keys which need values
67
+ # and were not called and have defaults, or raise error.
68
+ #
69
+ # The rest of arguments (non-keys) are either yielded or returned
70
+ # as an array.
71
+ #
72
+ # You can optionally set other arguments than specified in constructor
73
+ #
74
+ # @param [Array] args to parse. If specified, arguments passed to constructor
75
+ # will be ignored and lost
76
+ # @return [Array] non-keys arguments (keys afer '--' or other arguments)
77
+ # @yield [String] non keys argumenrs (same as returned)
78
+ def parse args=nil
79
+ @args = args if args
80
+ no_more_keys = false
81
+ rest = []
82
+ while !@args.empty?
83
+ a = @args.shift
84
+ case
85
+ when no_more_keys
86
+ rest << a
87
+ when (data = @keys[a])
88
+ @required.delete data
89
+ if data.needs_value
90
+ value = @args.shift or raise "Value needed for key #{a}"
91
+ data.block.call value
92
+ else
93
+ data.block.call
94
+ end
95
+ when a == '--'
96
+ no_more_keys = true
97
+ when a[0] == '-'
98
+ raise Error, "Unknown key #{a}"
99
+ else
100
+ rest << a
101
+ end
102
+ end
103
+ @required.each { |data|
104
+ raise Error, "Required key is missing: #{data.key}" if !data.default_set
105
+ data.block.call data.default
106
+ }
107
+ block_given? and rest.each { |a| yield a }
108
+ rest
109
+ end
110
+
111
+ # Generate keys documentation multiline text
112
+ def keys_doc
113
+ res = []
114
+ @docs.each { |d|
115
+ keys = [d.key] + d.aliases
116
+ str = "\t#{keys.join(',')}"
117
+ if d.needs_value
118
+ str += " value"
119
+ if d.default
120
+ str += " (default: #{d.default})" if d.default
121
+ else
122
+ str += ' (optional)'
123
+ end
124
+ end
125
+ res << str
126
+ d.doc and d.doc.split("\n").each{ |l| res << "\t\t#{l}" }
127
+ }
128
+ res.join("\n")
129
+ end
130
+
131
+ end
132
+
133
+ end
data/lib/h8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module H8
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
File without changes
@@ -0,0 +1,4 @@
1
+ @.puts ?= ->
2
+ # Do nothing if not set
3
+
4
+ @.globalsIncluded = true
@@ -0,0 +1,50 @@
1
+ errorsCount = 0
2
+
3
+ class TestFailed extends Error
4
+
5
+ fail = (msg) ->
6
+ msg = "Failed: #{msg}\n"
7
+ errorsCount++
8
+ try
9
+ throw Error()
10
+ catch e
11
+ msg += e.stack.split("\n")[3]+' '+__FILE__
12
+ console.error msg
13
+
14
+ ok = (condition, message='') ->
15
+ condition or fail "condition is not true"
16
+
17
+ gt = (a, b, message = '') ->
18
+ unless a > b
19
+ fail "#{a} > #{b} #{message}"
20
+
21
+ ge = (a, b, message = '') ->
22
+ unless a >= b
23
+ fail "#{a} >= #{b} #{message}"
24
+
25
+ lt = (a, b, message = '') ->
26
+ unless a < b
27
+ fail "#{a} < #{b} #{message}"
28
+
29
+ le = (a, b, message = '') ->
30
+ unless a <= b
31
+ fail "#{a} <= #{b} #{message}"
32
+
33
+ eq = (a, b, message = '') ->
34
+ unless a == b
35
+ fail "#{a} == #{b} #{message}"
36
+
37
+ ne = (a, b, message = '') ->
38
+ unless a != b
39
+ fail "#{a} != #{b} #{message}"
40
+
41
+
42
+ ok File.dirname(__FILE__).match(/spec\/coffee$/)
43
+ eq File.extname(__FILE__), '.coffee'
44
+
45
+ eq File.basename(__FILE__), 'cli_tests.coffee'
46
+
47
+ if errorsCount > 0
48
+ print "#{errorsCount} tests failed"
49
+ else
50
+ print "All tests passed"