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.
@@ -0,0 +1,48 @@
1
+ pad = (n, len) ->
2
+ len ?= 3
3
+ res = n.toString()
4
+ res = ' '+res while res.length < len
5
+ res
6
+
7
+ shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [-2, -1]]
8
+
9
+ class Solver
10
+
11
+ constructor: (@n, @left_free) ->
12
+ @nn = @n * @n
13
+ @n2 = @n + @n
14
+ @desk = []
15
+ @depth = 0
16
+ for r in [0...@n]
17
+ @desk.push (0 for col in [0...@n])
18
+ @solve 0, 0
19
+
20
+ solve: (r, c) ->
21
+ @desk[r][c] = ++@depth
22
+ return true if @depth + @left_free >= @nn
23
+ for [r1, c1] in @moves(r, c)
24
+ return true if @solve(r1, c1)
25
+ @desk[r][c] = 0
26
+ @depth--
27
+ false
28
+
29
+ # Coffeescript does not support generators
30
+ moves: (r, c) ->
31
+ res = []
32
+ for [sr, sc] in shifts
33
+ r1 = r + sr
34
+ if 0 <= r1 < @n
35
+ c1 = c + sc
36
+ if 0 <= c1 < @n && @desk[r1][c1]==0
37
+ res.push [r1, c1]
38
+ res
39
+
40
+ toString: ->
41
+ res = []
42
+ for r in [0...@n]
43
+ res.push ( (if x==0 then ' .' else pad(x,3)) for x in @desk[r]).join('')
44
+ res.join "\n"
45
+
46
+ return (n, left) ->
47
+ new Solver(n, left).toString()
48
+
@@ -0,0 +1,70 @@
1
+ require './tools'
2
+
3
+ class Solver
4
+
5
+ def initialize rank, leave_free=0
6
+ @n, @nn = rank, rank*rank
7
+ @n2 = @n+@n
8
+ @leave_free = leave_free
9
+ @desk = []
10
+ @n.times { @desk << [0] * @n }
11
+ @depth = 0
12
+ solve 0, 0
13
+ end
14
+
15
+ def solve r, c
16
+ @desk[r][c] = (@depth+=1)
17
+ return true if @depth == @nn-@leave_free
18
+ moves(r, c) { |r1, c1|
19
+ return true if solve(r1, c1)
20
+ }
21
+ @desk[r][c] = 0
22
+ @depth -= 1
23
+ false
24
+ end
25
+
26
+ @@shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [-2, -1]]
27
+
28
+ def moves r, c
29
+ @@shifts.each { |sr, sc|
30
+ r1 = r + sr
31
+ if r1 >= 0 && r1 < @n
32
+ c1 = c + sc
33
+ if c1 >= 0 && c1 < @n
34
+ yield r1, c1 if @desk[r1][c1] == 0
35
+ end
36
+ end
37
+ }
38
+ end
39
+
40
+ def to_s
41
+ res = []
42
+ @n.times do |row|
43
+ res << @n.times.map { |col|
44
+ d = @desk[row][col]
45
+ d == 0 ? ' .' : ("%3d" % d)
46
+ }.join('')
47
+ end
48
+ res.join "\n"
49
+ end
50
+
51
+ end
52
+
53
+ cs = js_context.eval coffee(:knightsmove)
54
+
55
+ N, L = 7, 3
56
+
57
+ res1 = res2 = 0
58
+ timing('total') {
59
+ tt = []
60
+ tt << Thread.start { timing('ruby') { res1 = Solver.new(N, L).to_s } }
61
+ tt << Thread.start { timing('coffee') { res2 = cs.call(N, L) } }
62
+ tt.each &:join
63
+ }
64
+
65
+ if res1 != res2
66
+ puts "WRONG RESULTS test data can not be trusted"
67
+ puts "Ruby:\n#{res1}"
68
+ puts "Coffee:\n#{res2}"
69
+ end
70
+
@@ -0,0 +1,12 @@
1
+ return (text) ->
2
+ words = {}
3
+ freq = []
4
+ for w in text.split(/\s+/)
5
+ w = w.toLowerCase()
6
+ continue if w == 'which' || w == 'from' || w.length < 4
7
+ w = w[2..-1]
8
+ unless (rec = words[w])?.count++
9
+ freq.push (words[w] = { word: w, count: 1})
10
+ freq.sort (a,b) ->
11
+ b.count - a.count
12
+ freq[0..10]
@@ -0,0 +1,51 @@
1
+ require 'h8'
2
+ require 'pp'
3
+ require './tools'
4
+
5
+ def process_text text
6
+ words = {}
7
+ text.split(/\s+/).each { |w|
8
+ w.downcase!
9
+ next if w == 'which' || w == 'from' || w.length < 4
10
+ w = w[2..-1]
11
+ rec = words[w] ||= { word: w, count: 0 }
12
+ rec[:count] += 1
13
+ }
14
+ words.values.sort { |a, b| b[:count] <=> a[:count] }[0..10]
15
+ end
16
+
17
+ base = File.dirname(File.expand_path(__FILE__))
18
+
19
+ text = open(base+'/big.txt').read
20
+ text = text * 2
21
+
22
+ cxt = js_context
23
+
24
+ coffee_process = cxt.eval coffee(:process_text)
25
+
26
+ coffee_res = ruby_res = nil
27
+
28
+ t1 = Thread.start {
29
+ timing "ruby" do
30
+ ruby_res = process_text text
31
+ end
32
+ }
33
+
34
+ t2 = Thread.start {
35
+ timing "coffee" do
36
+ coffee_res = coffee_process.call text
37
+ end
38
+ }
39
+
40
+ timing 'total' do
41
+ t1.join
42
+ t2.join
43
+ end
44
+
45
+ # pp coffee_res.to_ruby[0..4]
46
+ # pp ruby_res[0..4]
47
+ 5.times { |n|
48
+ coffee_res[n].word == ruby_res[n][:word] or raise "Words are different"
49
+ coffee_res[n].count == ruby_res[n][:count] or raise "counts are different"
50
+ }
51
+
@@ -0,0 +1,21 @@
1
+ require 'h8'
2
+
3
+ def timing name
4
+ s = Time.now
5
+ yield
6
+ puts "#{name}\t: #{Time.now - s}"
7
+ rescue
8
+ puts "*** #{$!}"
9
+ raise
10
+ end
11
+
12
+ def js_context
13
+ cxt = H8::Context.new
14
+ cxt[:print] = -> (*args) { puts args.join(' ') }
15
+ cxt
16
+ end
17
+
18
+ def coffee script_file_name
19
+ @base ||= File.dirname(File.expand_path(__FILE__))
20
+ H8::Coffee.compile open("#{@base}/#{script_file_name}.coffee").read
21
+ end
data/bin/h8 ADDED
@@ -0,0 +1,12 @@
1
+ #!/bin/env ruby
2
+ require 'h8'
3
+ require 'h8/command'
4
+
5
+ cmd = nil
6
+ begin
7
+ cmd = H8::Command.new(*ARGV)
8
+ rescue Exception => e
9
+ STDERR.puts "Error: #{e}\n\n#{e.backtrace.join("\n")}"
10
+ STDERR.puts cmd.usage
11
+ exit 10
12
+ end
data/ext/h8/h8.cpp CHANGED
@@ -99,14 +99,16 @@ void h8::H8::invoke(v8::Handle<v8::Script> script, Local<Value>& result) {
99
99
  #endif
100
100
  }
101
101
 
102
- v8::Handle<v8::Value> h8::H8::eval(const char* script_utf, unsigned max_ms) {
102
+ v8::Handle<v8::Value> h8::H8::eval(const char* script_utf, unsigned max_ms,const char* source_name) {
103
103
  v8::EscapableHandleScope escape(isolate);
104
104
  Local<Value> result;
105
105
 
106
106
  Handle<v8::String> script_source = String::NewFromUtf8(isolate, script_utf);
107
107
  v8::Handle<v8::Script> script;
108
108
  JsCatcher try_catch(this);
109
- v8::ScriptOrigin origin(String::NewFromUtf8(isolate, "eval"));
109
+ if( source_name == NULL)
110
+ source_name = "eval";
111
+ v8::ScriptOrigin origin(String::NewFromUtf8(isolate, source_name));
110
112
 
111
113
  script = v8::Script::Compile(script_source, &origin);
112
114
 
data/ext/h8/h8.h CHANGED
@@ -125,11 +125,11 @@ public:
125
125
  * to this value, JsTimeoutError will be thrown if exceeded
126
126
  * \return the value returned by the script.
127
127
  */
128
- Handle<Value> eval(const char* script_utf, unsigned max_ms = 0);
128
+ Handle<Value> eval(const char* script_utf, unsigned max_ms = 0,const char* script_name=NULL);
129
129
 
130
- VALUE eval_to_ruby(const char* script_utf, int timeout = 0) {
130
+ VALUE eval_to_ruby(const char* script_utf, int timeout = 0,const char* script_name=NULL) {
131
131
  // TODO: throw ruby exception on error
132
- return to_ruby(eval(script_utf, timeout));
132
+ return to_ruby(eval(script_utf, timeout, script_name));
133
133
  }
134
134
 
135
135
  Handle<Context> getContext() {
@@ -159,6 +159,11 @@ public:
159
159
  getContext()->Global()->Set(js(name), to_js(value));
160
160
  }
161
161
 
162
+ void gc() {
163
+ // puts("H8 GC");
164
+ while(!isolate->IdleNotification(500)) {}
165
+ }
166
+
162
167
  Local<Value> to_js(VALUE ruby_value) {
163
168
  switch (TYPE(ruby_value)) {
164
169
  case T_STRING:
data/ext/h8/js_gate.h CHANGED
@@ -135,6 +135,9 @@ public:
135
135
  object()->Set(v8_name, h8->to_js(value));
136
136
  }
137
137
 
138
+ /**
139
+ * Access indexed property from ruby environment
140
+ */
138
141
  VALUE get_index(VALUE index) {
139
142
  H8::Scope scope(h8);
140
143
  return h8->to_ruby(object()->Get(NUM2INT(index)));
@@ -148,11 +151,18 @@ public:
148
151
  return value()->IsString() ? Qtrue : Qfalse;
149
152
  }
150
153
 
154
+ /**
155
+ * True if the wrapped object is a function
156
+ */
151
157
  VALUE is_function() {
152
158
  H8::Scope scope(h8);
153
159
  return value()->IsFunction();
154
160
  }
155
161
 
162
+ /**
163
+ * Usually unneeded function, as H8 converts undefined values to
164
+ * H8::Undefined
165
+ */
156
166
  VALUE is_undefined() {
157
167
  H8::Scope scope(h8);
158
168
  return value()->IsUndefined() ? Qtrue : Qfalse;
@@ -166,11 +176,18 @@ public:
166
176
  return apply(h8->getContext()->Global(), args);
167
177
  }
168
178
 
179
+ /**
180
+ * apply wrapped function to a given 'this' value and arguments
181
+ * wrapped in the ruby array
182
+ */
169
183
  VALUE apply(VALUE self, VALUE args) const {
170
184
  H8::Scope scope(h8);
171
185
  return apply(h8->gateObject(self), args);
172
186
  }
173
187
 
188
+ /**
189
+ * @return bound ruby H8::Context instance
190
+ */
174
191
  VALUE ruby_context() const {
175
192
  return h8->ruby_context();
176
193
  }
@@ -185,6 +202,8 @@ public:
185
202
  persistent_value.Reset();
186
203
  AllocatedResource::free();
187
204
  h8 = 0;
205
+ // It is used no more, and it will be GC'd by ruby, until then
206
+ // we can not delete it!
188
207
  }
189
208
 
190
209
  virtual void rb_mark_gc() {
@@ -202,9 +221,11 @@ public:
202
221
  virtual ~JsGate() {
203
222
  if( h8 ) {
204
223
  Locker l(h8->getIsolate());
224
+ // puts("~JsGate1");
205
225
  persistent_value.Reset();
206
226
  }
207
227
  else {
228
+ // puts("~JsGate2");
208
229
  persistent_value.Reset();
209
230
  }
210
231
  }
@@ -220,6 +241,7 @@ private:
220
241
  }
221
242
 
222
243
  #include "ruby_gate.h"
244
+ #include <ruby/encoding.h>
223
245
 
224
246
  template<class T>
225
247
  VALUE h8::JsGate::to_ruby(H8* h8, const Handle<T>& value) {
@@ -228,7 +250,9 @@ VALUE h8::JsGate::to_ruby(H8* h8, const Handle<T>& value) {
228
250
  if (v->IsString()) {
229
251
  H8::Scope scope(h8);
230
252
  String::Utf8Value res(v);
231
- return *res ? rb_str_new2(*res) : Qnil;
253
+ if( *res )
254
+ return rb_enc_str_new(*res, res.length(), rb_utf8_encoding());
255
+ return Qnil;
232
256
  }
233
257
  if (v->IsInt32()) {
234
258
  return INT2FIX(v->Int32Value());
data/ext/h8/main.cpp CHANGED
@@ -29,7 +29,7 @@ VALUE protect_ruby(const std::function<VALUE()> &block) {
29
29
  }
30
30
 
31
31
  static void rvalue_free(void* ptr) {
32
- delete (JsGate*) ptr;
32
+ delete ((JsGate*) ptr);
33
33
  }
34
34
 
35
35
  static void rvalue_mark(void* ptr) {
@@ -126,21 +126,27 @@ inline H8* rc(VALUE self) {
126
126
  return prcxt;
127
127
  }
128
128
 
129
- static VALUE context_eval(VALUE self, VALUE script,VALUE timeout) {
129
+ static VALUE context_eval(VALUE self, VALUE script,VALUE timeout,VALUE script_name_ruby) {
130
130
  return protect_ruby([&] {
131
131
  H8* cxt = rc(self);// v8::Locker l(cxt->getIsolate());
132
132
  H8::Scope s(cxt);
133
- return cxt->eval_to_ruby(StringValueCStr(script), FIX2INT(timeout));
133
+ const char* script_name = script_name_ruby != Qnil ? StringValueCStr(script_name_ruby) : NULL;
134
+ return cxt->eval_to_ruby(StringValueCStr(script), FIX2INT(timeout), script_name);
134
135
  });
135
136
  }
136
137
 
137
138
  static VALUE context_set_var(VALUE self, VALUE name, VALUE value) {
138
- return protect_ruby([=] {
139
+ return protect_ruby([&] {
139
140
  rc(self)->set_var(name, value);
140
141
  return Qnil;
141
142
  });
142
143
  }
143
144
 
145
+ static VALUE context_force_gc(VALUE self) {
146
+ rc(self)->gc();
147
+ return Qnil;
148
+ }
149
+
144
150
  static void context_free(void* ptr) {
145
151
  delete (H8*) ptr;
146
152
  }
@@ -176,9 +182,10 @@ void Init_h8(void) {
176
182
  context_class = rb_define_class_under(h8, "Context", rb_cObject);
177
183
  ruby_gate_class = rb_define_class_under(h8, "RubyGate", rb_cObject);
178
184
  rb_define_alloc_func(context_class, context_alloc);
179
- rb_define_method(context_class, "_eval", (ruby_method) context_eval, 2);
185
+ rb_define_method(context_class, "_eval", (ruby_method) context_eval, 3);
180
186
  rb_define_method(context_class, "_set_var", (ruby_method) context_set_var,
181
187
  2);
188
+ rb_define_method(context_class, "javascript_gc", (ruby_method) context_force_gc, 0);
182
189
 
183
190
  value_class = rb_define_class_under(h8, "Value", rb_cObject);
184
191
  rb_define_alloc_func(value_class, rvalue_alloc);
data/ext/h8/object_wrap.h CHANGED
@@ -26,111 +26,105 @@
26
26
  #include <include/v8.h>
27
27
  #include <assert.h>
28
28
 
29
-
30
29
  namespace h8 {
31
30
 
32
31
  class ObjectWrap {
33
- public:
34
- ObjectWrap() {
35
- refs_ = 0;
36
- }
37
-
38
-
39
- virtual ~ObjectWrap() {
40
- if (persistent().IsEmpty())
41
- return;
42
- assert(persistent().IsNearDeath());
43
- persistent().ClearWeak();
44
- persistent().Reset();
45
- }
46
-
47
-
48
- template <class T>
49
- static inline T* Unwrap(v8::Handle<v8::Object> handle) {
50
- assert(!handle.IsEmpty());
51
- assert(handle->InternalFieldCount() > 0);
52
- // Cast to ObjectWrap before casting to T. A direct cast from void
53
- // to T won't work right when T has more than one base class.
54
- void* ptr = handle->GetAlignedPointerFromInternalField(0);
55
- ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr);
56
- return static_cast<T*>(wrap);
57
- }
58
-
59
-
60
- inline v8::Local<v8::Object> handle() {
61
- return handle(v8::Isolate::GetCurrent());
62
- }
63
-
64
-
65
- inline v8::Local<v8::Object> handle(v8::Isolate* isolate) {
66
- return v8::Local<v8::Object>::New(isolate, persistent());
67
- }
68
-
69
-
70
- inline v8::Persistent<v8::Object>& persistent() {
71
- return handle_;
72
- }
73
-
74
-
75
- protected:
76
- inline void Wrap(v8::Handle<v8::Object> handle) {
77
- assert(persistent().IsEmpty());
78
- assert(handle->InternalFieldCount() > 0);
79
- handle->SetAlignedPointerInInternalField(0, this);
80
- persistent().Reset(v8::Isolate::GetCurrent(), handle);
81
- MakeWeak();
82
- }
83
-
84
-
85
- inline void MakeWeak(void) {
86
- persistent().SetWeak(this, WeakCallback);
87
- persistent().MarkIndependent();
88
- }
89
-
90
- /* Ref() marks the object as being attached to an event loop.
91
- * Refed objects will not be garbage collected, even if
92
- * all references are lost.
93
- */
94
- virtual void Ref() {
95
- assert(!persistent().IsEmpty());
96
- persistent().ClearWeak();
97
- refs_++;
98
- }
99
-
100
- /* Unref() marks an object as detached from the event loop. This is its
101
- * default state. When an object with a "weak" reference changes from
102
- * attached to detached state it will be freed. Be careful not to access
103
- * the object after making this call as it might be gone!
104
- * (A "weak reference" means an object that only has a
105
- * persistant handle.)
106
- *
107
- * DO NOT CALL THIS FROM DESTRUCTOR
108
- */
109
- virtual void Unref() {
110
- assert(!persistent().IsEmpty());
111
- assert(!persistent().IsWeak());
112
- assert(refs_ > 0);
113
- if (--refs_ == 0)
114
- MakeWeak();
115
- }
116
-
117
- int refs_; // ro
118
-
119
- private:
120
- static void WeakCallback(
121
- const v8::WeakCallbackData<v8::Object, ObjectWrap>& data) {
122
- v8::Isolate* isolate = data.GetIsolate();
123
- v8::HandleScope scope(isolate);
124
- ObjectWrap* wrap = data.GetParameter();
125
- assert(wrap->refs_ == 0);
126
- assert(wrap->handle_.IsNearDeath());
127
- assert(
128
- data.GetValue() == v8::Local<v8::Object>::New(isolate, wrap->handle_));
129
- wrap->handle_.Reset();
130
- delete wrap;
131
- }
132
-
133
- v8::Persistent<v8::Object> handle_;
32
+ public:
33
+ ObjectWrap() {
34
+ refs_ = 0;
35
+ }
36
+
37
+ virtual ~ObjectWrap() {
38
+ if (persistent().IsEmpty())
39
+ return;
40
+ assert(persistent().IsNearDeath());
41
+ persistent().ClearWeak();
42
+ persistent().Reset();
43
+ }
44
+
45
+ template<class T>
46
+ static inline T* Unwrap(v8::Handle<v8::Object> handle) {
47
+ assert(!handle.IsEmpty());
48
+ assert(handle->InternalFieldCount() > 0);
49
+ // Cast to ObjectWrap before casting to T. A direct cast from void
50
+ // to T won't work right when T has more than one base class.
51
+ void* ptr = handle->GetAlignedPointerFromInternalField(0);
52
+ ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr);
53
+ return static_cast<T*>(wrap);
54
+ }
55
+
56
+ inline v8::Local<v8::Object> handle() {
57
+ return handle(v8::Isolate::GetCurrent());
58
+ }
59
+
60
+ inline v8::Local<v8::Object> handle(v8::Isolate* isolate) {
61
+ return v8::Local<v8::Object>::New(isolate, persistent());
62
+ }
63
+
64
+ inline v8::Persistent<v8::Object>& persistent() {
65
+ return handle_;
66
+ }
67
+
68
+ protected:
69
+ inline void Wrap(v8::Handle<v8::Object> handle) {
70
+ assert(persistent().IsEmpty());
71
+ assert(handle->InternalFieldCount() > 0);
72
+ handle->SetAlignedPointerInInternalField(0, this);
73
+ persistent().Reset(v8::Isolate::GetCurrent(), handle);
74
+ MakeWeak();
75
+ }
76
+
77
+ inline void MakeWeak(void) {
78
+ persistent().SetWeak(this, WeakCallback);
79
+ persistent().MarkIndependent();
80
+ }
81
+
82
+ /* Ref() marks the object as being attached to an event loop.
83
+ * Refed objects will not be garbage collected, even if
84
+ * all references are lost.
85
+ */
86
+ virtual void Ref() {
87
+ assert(!persistent().IsEmpty());
88
+ persistent().ClearWeak();
89
+ refs_++;
90
+ }
91
+
92
+ /* Unref() marks an object as detached from the event loop. This is its
93
+ * default state. When an object with a "weak" reference changes from
94
+ * attached to detached state it will be freed. Be careful not to access
95
+ * the object after making this call as it might be gone!
96
+ * (A "weak reference" means an object that only has a
97
+ * persistant handle.)
98
+ *
99
+ * DO NOT CALL THIS FROM DESTRUCTOR
100
+ */
101
+ virtual void Unref() {
102
+ assert(!persistent().IsEmpty());
103
+ assert(!persistent().IsWeak());
104
+ assert(refs_ > 0);
105
+ if (--refs_ == 0)
106
+ MakeWeak();
107
+ }
108
+
109
+ int refs_; // ro
110
+
111
+ private:
112
+ static void WeakCallback(
113
+ const v8::WeakCallbackData<v8::Object, ObjectWrap>& data) {
114
+ puts("WEAK CALLBACK!!");
115
+ v8::Isolate* isolate = data.GetIsolate();
116
+ v8::HandleScope scope(isolate);
117
+ ObjectWrap* wrap = data.GetParameter();
118
+ assert(wrap->refs_ == 0);
119
+ assert(wrap->handle_.IsNearDeath());
120
+ assert(
121
+ data.GetValue()
122
+ == v8::Local<v8::Object>::New(isolate, wrap->handle_));
123
+ wrap->handle_.Reset();
124
+ delete wrap;
125
+ }
126
+
127
+ v8::Persistent<v8::Object> handle_;
134
128
  };
135
129
 
136
130
  } // namespace node