flok 0.0.38 → 0.0.39

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/drivers/chrome/src/dispatch.js +41 -6
  3. data/app/drivers/chrome/src/persist.js +1 -10
  4. data/app/kern/dispatch.js +17 -23
  5. data/app/kern/gen_id.js +8 -0
  6. data/app/kern/macro.rb +20 -18
  7. data/app/kern/pagers/pg_spec0.js +20 -0
  8. data/app/kern/services/vm.rb +176 -30
  9. data/docs/client_api.md +3 -1
  10. data/docs/compilation.md +1 -1
  11. data/docs/dispatch.md +91 -0
  12. data/docs/kernel_api.md +3 -2
  13. data/docs/messaging.md +6 -1
  14. data/docs/mod/persist.md +4 -3
  15. data/docs/project_layout.md +2 -2
  16. data/docs/services/vm.md +116 -41
  17. data/docs/services/vm/pagers.md +38 -46
  18. data/lib/flok.rb +1 -0
  19. data/lib/flok/build.rb +3 -4
  20. data/lib/flok/macro.rb +27 -0
  21. data/lib/flok/services_compiler.rb +12 -8
  22. data/lib/flok/user_compiler.rb +131 -4
  23. data/lib/flok/version.rb +1 -1
  24. data/spec/env/kern.rb +71 -0
  25. data/spec/etc/macro_spec.rb +3 -8
  26. data/spec/etc/service_compiler/service3.rb +27 -0
  27. data/spec/etc/services_compiler_spec.rb +35 -27
  28. data/spec/iface/driver/dispatch_spec.rb +20 -0
  29. data/spec/iface/driver/persist_spec.rb +9 -24
  30. data/spec/iface/kern/ping_spec.rb +3 -24
  31. data/spec/kern/assets/vm/config4.rb +12 -0
  32. data/spec/kern/assets/vm/controller10.rb +26 -0
  33. data/spec/kern/assets/vm/controller11.rb +33 -0
  34. data/spec/kern/assets/vm/controller12.rb +45 -0
  35. data/spec/kern/assets/vm/controller13.rb +40 -0
  36. data/spec/kern/assets/vm/controller14.rb +14 -0
  37. data/spec/kern/assets/vm/controller15.rb +15 -0
  38. data/spec/kern/assets/vm/controller16.rb +29 -0
  39. data/spec/kern/assets/vm/controller17.rb +30 -0
  40. data/spec/kern/assets/vm/controller18.rb +28 -0
  41. data/spec/kern/assets/vm/controller19.rb +14 -0
  42. data/spec/kern/assets/vm/controller19b.rb +15 -0
  43. data/spec/kern/assets/vm/controller20.rb +19 -0
  44. data/spec/kern/assets/vm/controller21.rb +40 -0
  45. data/spec/kern/assets/vm/controller7.rb +18 -0
  46. data/spec/kern/assets/vm/controller8.rb +38 -0
  47. data/spec/kern/assets/vm/controller8b.rb +18 -0
  48. data/spec/kern/assets/vm/controller9.rb +20 -0
  49. data/spec/kern/assets/vm/controller_exc_2watch.rb +15 -0
  50. data/spec/kern/assets/vm/controller_exc_ewatch.rb +14 -0
  51. data/spec/kern/assets/vm/macros/copy_page_c.rb +23 -0
  52. data/spec/kern/assets/vm/macros/entry_del_c.rb +18 -0
  53. data/spec/kern/assets/vm/macros/entry_insert_c.rb +21 -0
  54. data/spec/kern/assets/vm/macros/entry_mutable_c.rb +33 -0
  55. data/spec/kern/assets/vm/macros/new_page_c.rb +7 -0
  56. data/spec/kern/assets/vm/macros/new_page_c2.rb +7 -0
  57. data/spec/kern/assets/vm/macros/set_page_head_c.rb +18 -0
  58. data/spec/kern/assets/vm/macros/set_page_next_c.rb +18 -0
  59. data/spec/kern/controller_macro_spec.rb +186 -0
  60. data/spec/kern/dispatch_spec.rb +125 -0
  61. data/spec/kern/functions_spec.rb +15 -0
  62. data/spec/kern/vm_service_spec.rb +874 -173
  63. metadata +70 -5
  64. data/docs/scheduling.md +0 -46
  65. data/spec/kern/rest_service_spec.rb +0 -45
data/lib/flok.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "flok/macro"
1
2
  require "flok/version"
2
3
  require "flok/utilities"
3
4
  require "flok/build"
data/lib/flok/build.rb CHANGED
@@ -66,9 +66,8 @@ module Flok
66
66
  Flok.src_glob("js", './app/kern/pagers/', "#{build_path}/glob/3kern.pre_macro.js")
67
67
 
68
68
  #5. All js files in `./products/$PLATFORM/glob/{2,3}kern.pre_macro.js` are run through `./app/kern/macro.rb's macro_process` and then sent to ./products/$PLATFORM/glob/{2,3}kern.js
69
- require './app/kern/macro.rb'
70
- File.write("#{build_path}/glob/2kern.pre_macro.js", macro_process(File.read("#{build_path}/glob/2kern.pre_macro.js")))
71
- File.write("#{build_path}/glob/3kern.pre_macro.js", macro_process(File.read("#{build_path}/glob/3kern.pre_macro.js")))
69
+ File.write("#{build_path}/glob/2kern.pre_macro.js", Flok.macro_process(File.read("#{build_path}/glob/2kern.pre_macro.js")))
70
+ File.write("#{build_path}/glob/3kern.pre_macro.js", Flok.macro_process(File.read("#{build_path}/glob/3kern.pre_macro.js")))
72
71
 
73
72
  #6. All js files are globbed from `./products/$platform/glob` and combined into `./products/$platform/glob/application.js.erb`
74
73
  Flok.src_glob("js", "#{build_path}/glob", "#{build_path}/glob/application.js.erb")
@@ -95,7 +94,7 @@ module Flok
95
94
  mods.each do |mod|
96
95
  s = File.read("./app/kern/mod/#{mod}.js")
97
96
  open("#{build_path}/glob/application.js.erb", "a") do |f|
98
- f.puts macro_process(s)
97
+ f.puts Flok.macro_process(s)
99
98
  end
100
99
  end
101
100
 
data/lib/flok/macro.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Flok
2
+ #Process one js code file at a time
3
+ def self.macro_process text
4
+ out = StringIO.new
5
+
6
+ text.split("\n").each do |l|
7
+ #Send macro
8
+ if l =~ /SEND/
9
+ l.strip!
10
+ l.gsub!(/SEND\(/, "")
11
+ l.gsub! /\)$/, ""
12
+ l.gsub! /\);$/, ""
13
+ o = l.split(",").map{|e| e.strip}
14
+
15
+ queue_name = o.shift.gsub(/"/, "")
16
+
17
+ res = %{#{queue_name}_q.push([#{o.count-1}, #{o.join(", ")}])}
18
+ out.puts res
19
+ else
20
+ out.puts l
21
+ end
22
+ end
23
+
24
+ return out.string
25
+ end
26
+ end
27
+
@@ -17,7 +17,7 @@ module Flok
17
17
  context = ServicesCompilerContext.new(config_context)
18
18
  context.instance_eval(rb_src, __FILE__, __LINE__)
19
19
  context.ready
20
-
20
+
21
21
  @src = ""
22
22
  services_erb = File.read File.join(File.dirname(__FILE__), "./service_compiler_templates/services.js.erb")
23
23
  services_renderer = ERB.new(services_erb)
@@ -95,6 +95,9 @@ module Flok
95
95
 
96
96
  #These are for every 5.seconds
97
97
  @every_handlers = []
98
+
99
+ @debug = true if ENV["FLOK_ENV"] == "DEBUG"
100
+ @release = true if ENV["FLOK_ENV"] == "RELEASE"
98
101
  end
99
102
 
100
103
  def get_on_init
@@ -108,32 +111,32 @@ module Flok
108
111
  def global(str)
109
112
  render = ERB.new(str)
110
113
  str = render.result(binding)
111
- @_global = str
114
+ @_global = macro(str)
112
115
  end
113
116
 
114
117
  def on_wakeup(str)
115
118
  render = ERB.new(str)
116
119
  str = render.result(binding)
117
- @_on_wakeup = str
120
+ @_on_wakeup = macro(str)
118
121
  end
119
122
 
120
123
  def on_sleep(str)
121
124
  render = ERB.new(str)
122
125
  str = render.result(binding)
123
126
 
124
- @_on_sleep = str
127
+ @_on_sleep = macro(str)
125
128
  end
126
129
 
127
130
  def on_connect(str)
128
131
  render = ERB.new(str)
129
132
  str = render.result(binding)
130
- @_on_connect = str
133
+ @_on_connect = macro(str)
131
134
  end
132
135
 
133
136
  def on_disconnect(str)
134
137
  render = ERB.new(str)
135
138
  str = render.result(binding)
136
- @_on_disconnect = str
139
+ @_on_disconnect = macro(str)
137
140
  end
138
141
 
139
142
  def on(name, str)
@@ -142,7 +145,7 @@ module Flok
142
145
 
143
146
  @event_handlers << {
144
147
  :name => name,
145
- :str => str
148
+ :str => macro(str)
146
149
  }
147
150
  end
148
151
 
@@ -150,7 +153,7 @@ module Flok
150
153
  @every_handlers << {
151
154
  :name => "#{seconds}_sec_#{SecureRandom.hex[0..6]}",
152
155
  :ticks => seconds*4,
153
- :str => str
156
+ :str => macro(str)
154
157
  }
155
158
  end
156
159
 
@@ -163,6 +166,7 @@ module Flok
163
166
  end
164
167
 
165
168
  def macro text
169
+ return Flok.macro_process(text)
166
170
  #out = StringIO.new
167
171
 
168
172
  #text.split("\n").each do |l|
@@ -14,7 +14,7 @@ module Flok
14
14
  ctable_erb = File.read File.join(File.dirname(__FILE__), "./user_compiler_templates/ctable.js.erb")
15
15
  ctable_renderer = ERB.new(ctable_erb)
16
16
  @src << ctable_renderer.result(context.get_binding)
17
-
17
+
18
18
  return @src
19
19
  end
20
20
  end
@@ -169,7 +169,6 @@ module Flok
169
169
  int_event(vcs[i], #{event_name}, #{info});
170
170
  }
171
171
  }
172
-
173
172
  #GOTO(action_name)
174
173
  elsif l =~ /Goto/
175
174
  l.strip!
@@ -240,12 +239,140 @@ module Flok
240
239
  name = o.shift.gsub(/"/, "")
241
240
  ename = o.shift.gsub(/"/, "")
242
241
  info = o.shift.gsub(/"/, "")
243
-
244
242
  raise "You tried to Request the service #{name.inspect}, but you haven't added that to your 'services' for this controller (#{@controller.name.inspect})" unless @controller._services.include? name
245
-
246
243
  out << %{
247
244
  #{name}_on_#{ename}(__base__, #{info});
248
245
  }
246
+ #VM Page macros
247
+ elsif l =~ /NewPage/
248
+ le = (l.split /NewPage/)
249
+ lvar = le[0].strip #Probably var x =
250
+ exp = le[1].strip
251
+
252
+ #For CopyPage(original_page), page_var is original_page
253
+ #This only supports variable names at this time
254
+ exp.match /\((.*)\);?/
255
+
256
+ #Get the id value the user wants, but we have to be careful
257
+ #because if nothing is passed, then we need to set it to null
258
+ id_var = $1.strip
259
+ if id_var == ""
260
+ id_var = "null"
261
+ end
262
+
263
+ out << %{
264
+ #{lvar} {
265
+ _head: null,
266
+ _next: null,
267
+ entries: [],
268
+ _id: #{id_var},
269
+ }
270
+ }
271
+ elsif l =~ /CopyPage/
272
+ le = (l.split /CopyPage/)
273
+ lvar = le[0].strip #Probably var x =
274
+ exp = le[1].strip
275
+
276
+ #For CopyPage(original_page), page_var is original_page
277
+ #This only supports variable names at this time
278
+ exp.match /\((.*)\);?/
279
+ page_var = $1
280
+
281
+ out << %{
282
+ var __page__ = {
283
+ _head: #{page_var}._head,
284
+ _next: #{page_var}._next,
285
+ _id: #{page_var}._id,
286
+ entries: [],
287
+ }
288
+
289
+ //This is a shallow clone, but we own this array
290
+ //When a mutable entry needs to be created, an entry will be cloned
291
+ //and swappend out
292
+ for (var i = 0; i < #{page_var}.entries.length; ++i) {
293
+ __page__.entries.push(#{page_var}.entries[i]);
294
+ }
295
+
296
+ #{lvar} __page__;
297
+ }
298
+ elsif l =~ /EntryDel/
299
+ le = (l.split /EntryDel/)
300
+ lvar = le[0].strip #Probably var x =
301
+ exp = le[1].strip
302
+
303
+ #For CopyPage(original_page), page_var is original_page
304
+ #This only supports variable names at this time
305
+ exp.match /\((.*?),(.*)\);?/
306
+ page_var = $1
307
+ index_var = $2
308
+
309
+ out << %{
310
+ #{page_var}.entries.splice(#{index_var}, 1);
311
+ }
312
+
313
+ elsif l =~ /EntryInsert/
314
+ le = (l.split /EntryInsert/)
315
+ lvar = le[0].strip #Probably var x =
316
+ exp = le[1].strip
317
+
318
+ #For CopyPage(original_page), page_var is original_page
319
+ #This only supports variable names at this time
320
+ exp.match /\((.*?),(.*),(.*)\);?/
321
+ page_var = $1
322
+ index_var = $2
323
+ entry_var = $3
324
+
325
+ out << %{
326
+ #{entry_var}._id = gen_id();
327
+ #{entry_var}._sig = gen_id();
328
+ #{page_var}.entries.splice(#{index_var}, 0, #{entry_var});
329
+ }
330
+
331
+ elsif l =~ /SetPageNext/
332
+ le = (l.split /SetPageNext/)
333
+ lvar = le[0].strip #Probably var x =
334
+ exp = le[1].strip
335
+
336
+ #For CopyPage(original_page), page_var is original_page
337
+ #This only supports variable names at this time
338
+ exp.match /\((.*?),(.*)\);?/
339
+ page_var = $1
340
+ value_var = $2
341
+
342
+ out << %{
343
+ #{page_var}._next = #{value_var};
344
+ }
345
+
346
+ elsif l =~ /SetPageHead/
347
+ le = (l.split /SetPageHead/)
348
+ lvar = le[0].strip #Probably var x =
349
+ exp = le[1].strip
350
+
351
+ #For CopyPage(original_page), page_var is original_page
352
+ #This only supports variable names at this time
353
+ exp.match /\((.*?),(.*)\);?/
354
+ page_var = $1
355
+ value_var = $2
356
+
357
+ out << %{
358
+ #{page_var}._head = #{value_var};
359
+ }
360
+
361
+ elsif l =~ /EntryMutable/
362
+ le = (l.split /EntryMutable/)
363
+ lvar = le[0].strip #Probably var x =
364
+ exp = le[1].strip
365
+
366
+ #For CopyPage(original_page), page_var is original_page
367
+ #This only supports variable names at this time
368
+ exp.match /\((.*?),(.*)\);?/
369
+ page_var = $1
370
+ index_var = $2
371
+
372
+ out << %{
373
+ //Duplicate entry
374
+ #{page_var}.entries.splice(#{index_var}, 1, JSON.parse(JSON.stringify(#{page_var}.entries[#{index_var}])));
375
+ }
249
376
  else
250
377
  out.puts l
251
378
  end
data/lib/flok/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Flok
2
- VERSION = "0.0.38"
2
+ VERSION = "0.0.39"
3
3
  end
data/spec/env/kern.rb CHANGED
@@ -4,6 +4,10 @@ require './spec/lib/temp_dir'
4
4
 
5
5
  shared_context "kern" do
6
6
  before(:each) do
7
+ reset_for_ctx
8
+ end
9
+
10
+ def reset_for_ctx
7
11
  res=system('rake build:world')
8
12
  raise "Could not run build:world" unless res
9
13
  @ctx = V8::Context.new
@@ -15,6 +19,16 @@ shared_context "kern" do
15
19
  end
16
20
  end
17
21
 
22
+ class V8::Context
23
+ def dump variable
24
+ json_res = self.eval %{
25
+ JSON.stringify(#{variable});
26
+ }
27
+
28
+ return JSON.parse(json_res)
29
+ end
30
+ end
31
+
18
32
  #Execute flok binary with a command
19
33
  def flok args
20
34
  #Get path to the flok binary relative to this file
@@ -44,6 +58,7 @@ shared_context "kern" do
44
58
  #Execute
45
59
  @driver = FakeDriverContext.new
46
60
  v8 = V8::Context.new(:with => @driver)
61
+ @ctx = v8
47
62
  @driver.ctx = v8
48
63
  v8.eval %{
49
64
  //We must convert this to JSON because the fake driver will receive
@@ -74,6 +89,12 @@ shared_context "kern" do
74
89
  @q += JSON.parse(q)
75
90
  end
76
91
 
92
+ #When you're running these unit tests, you may need to log, but you will
93
+ #need to remove any _log statements before running other tests!
94
+ def log(msg)
95
+ $stderr.puts "v8: #{msg}"
96
+ end
97
+
77
98
  #Expect a certain message, with some arguments, and a certain priority
78
99
  #expect("if_init_view", ["test_view", {}]) === [[0, 4, "if_init_view", "test_view", {}]]
79
100
  def mexpect(msg_name, msg_args, priority=0)
@@ -96,6 +117,50 @@ shared_context "kern" do
96
117
  expect(priority).to eq(@cp)
97
118
  end
98
119
 
120
+ #Ignore all messages until this one is received, then keep that one in the queue
121
+ #There may be a lot going on and you're only interested in a part.
122
+ #If priority is nil, it won't matter what the priority is, useful for checking exceptions
123
+ #for non-existant messages
124
+ def ignore_up_to msg_name, priority=nil
125
+ @did_get = []
126
+
127
+ loop do
128
+ if @q.count == 0 and @cq.count == 0
129
+ raise "Waited for the message #{msg_name.inspect} but never got it... did get: \n * #{@did_get.join("\n * ")}"
130
+ end
131
+ #Dequeue from multi-priority queue if possible
132
+ if @cq.nil? or @cq.count == 0
133
+ @cq = @q.shift
134
+ @cp = @cq.shift #save priority
135
+ end
136
+
137
+ #Check to see if it's the correct item
138
+ arg_len = @cq.shift
139
+ name = @cq.shift
140
+ if arg_len.class == String
141
+ $stderr.puts "Arg len is: #{arg_len.inspect}"
142
+ $stderr.puts "Name is #{name.inspect}"
143
+ end
144
+ args = @cq.shift(arg_len)
145
+
146
+ @did_get << name
147
+
148
+ if name == msg_name
149
+ if priority
150
+ raise "Found the message #{msg_name.inspect} while calling ignore_up_to... but it's the wrong priority: #{@cp}, should be #{priority}" if @cp != priority
151
+ end
152
+
153
+ #Unshift everything in reverse order, we are only peeking here...
154
+ args.reverse.each do |a|
155
+ @cq.unshift a
156
+ end
157
+ @cq.unshift name
158
+ @cq.unshift arg_len
159
+ break
160
+ end
161
+ end
162
+ end
163
+
99
164
  #Retrieve a message, we at least expect a name and priority
100
165
  def get msg_name, priority=0
101
166
  #Dequeue from multi-priority queue if possible
@@ -129,5 +194,11 @@ shared_context "kern" do
129
194
  int_dispatch(#{msg});
130
195
  }
131
196
  end
197
+
198
+ def dump_q
199
+ q = @q
200
+ @q = []
201
+ return q
202
+ end
132
203
  end
133
204
  end
@@ -3,14 +3,9 @@ require './spec/env/etc.rb'
3
3
 
4
4
 
5
5
  RSpec.describe "macro" do
6
- before(:each) do
7
- macro_file = './app/kern/macro.rb'
8
- load macro_file
9
- end
10
-
11
6
  it "Changes the text when SEND exists" do
12
7
  original = 'SEND("main", "if_net_req", url, params, tp)'
13
- text = macro_process original
8
+ text = Flok.macro_process original
14
9
 
15
10
  expect(original).not_to eq(text)
16
11
  expect(text.class).to eq(String)
@@ -19,14 +14,14 @@ RSpec.describe "macro" do
19
14
 
20
15
  it "Has same # of lines with SEND" do
21
16
  original = 'SEND("main", "if_net_req", url, params, tp)'
22
- text = macro_process original
17
+ text = Flok.macro_process original
23
18
 
24
19
  expect(text.split("\n").length).to eq(original.split("\n").length)
25
20
  end
26
21
 
27
22
  it "encodes SEND correctly" do
28
23
  original = 'SEND("main", "if_net_req", url, params, tp)'
29
- text = macro_process original
24
+ text = Flok.macro_process original
30
25
 
31
26
  @arr = []
32
27
  expected_code = %{main_q.push([3, "if_net_req", url, params, tp])}
@@ -0,0 +1,27 @@
1
+ service :my_service do
2
+ on_wakeup %{
3
+ on_wakeup_called = '#{@options[:hello]}';
4
+ SEND("main", "if_event", 3, "action", {});
5
+ }
6
+
7
+ on_sleep %{
8
+ on_sleep_called = true;
9
+ }
10
+
11
+ on_connect %{
12
+ on_connect_called_bp = bp;
13
+ }
14
+
15
+ on_disconnect %{
16
+ on_disconnect_called_bp = bp;
17
+ }
18
+
19
+ on "hello", %{
20
+ on_hello_called_bp = bp;
21
+ on_hello_called_params = JSON.stringify(params);
22
+ }
23
+
24
+ every 5.seconds, %{
25
+ on_every_5_sec_called = true;
26
+ }
27
+ end