h8 0.2.2 → 0.2.3

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.
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"