flok 0.0.102 → 0.0.103
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/app/drivers/chrome/pipe.rb +66 -51
- data/app/drivers/chrome/src/controller.js +20 -1
- data/app/drivers/chrome/src/hook.js +10 -12
- data/app/drivers/chrome/src/net.js +4 -4
- data/app/drivers/chrome/src/sockio.js +2 -2
- data/app/drivers/chrome/src/ui.js +18 -15
- data/app/kern/mod/event.js +3 -1
- data/app/kern/mod/hook.js +13 -1
- data/app/kern/mod/ui.js +71 -0
- data/docs/controllers.md +14 -0
- data/docs/dispatch.md +4 -2
- data/docs/kernel_api.md +1 -0
- data/docs/kernel_handbook/find_view.md +34 -0
- data/docs/kernel_handbook/hooks.md +12 -1
- data/docs/mod/controller.md +5 -2
- data/docs/mod/hook.md +4 -3
- data/docs/mod/persist.md +1 -1
- data/docs/mod/ui.md +1 -0
- data/docs/user_handbook/hooks.md +38 -14
- data/flok.gemspec +2 -0
- data/lib/flok/user_compiler.rb +18 -2
- data/lib/flok/user_compiler_templates/ctable.js.erb +1 -0
- data/lib/flok/user_hook_generators/goto.rb +32 -4
- data/lib/flok/version.rb +1 -1
- data/spec/env/iface.rb +38 -0
- data/spec/env/kern.rb +4 -0
- data/spec/iface/driver/controller_spec.rb +25 -6
- data/spec/iface/driver/dispatch_spec.rb +7 -0
- data/spec/iface/driver/hook_spec.rb +83 -7
- data/spec/iface/driver/net_spec.rb +50 -41
- data/spec/iface/driver/persist_spec.rb +47 -4
- data/spec/iface/driver/ping_spec.rb +1 -1
- data/spec/iface/driver/rtc_spec.rb +2 -2
- data/spec/iface/driver/sockio_spec.rb +4 -3
- data/spec/iface/driver/timer_spec.rb +20 -0
- data/spec/iface/driver/ui_spec.rb +27 -4
- data/spec/kern/assets/find_view/controller0.rb +24 -0
- data/spec/kern/assets/find_view/controller1.rb +35 -0
- data/spec/kern/assets/find_view/controller1a.rb +37 -0
- data/spec/kern/assets/find_view/controller2.rb +23 -0
- data/spec/kern/assets/find_view/controller3.rb +38 -0
- data/spec/kern/assets/find_view/controller4.rb +38 -0
- data/spec/kern/assets/find_view/controller5.rb +52 -0
- data/spec/kern/assets/find_view/controller6.rb +37 -0
- data/spec/kern/assets/find_view/controller7.rb +37 -0
- data/spec/kern/assets/find_view/controller8.rb +53 -0
- data/spec/kern/assets/find_view/controller9.rb +67 -0
- data/spec/kern/assets/hook_entry_points/controller0.rb +13 -1
- data/spec/kern/assets/push_count.rb +42 -0
- data/spec/kern/controller_spec.rb +34 -0
- data/spec/kern/find_view_spec.rb +269 -0
- data/spec/kern/hook_entry_points_and_manifest_spec.rb +60 -0
- data/spec/kern/hook_user_generators_spec.rb +100 -0
- data/spec/lib/helpers.rb +1 -2
- metadata +58 -2
@@ -0,0 +1,34 @@
|
|
1
|
+
#find_view
|
2
|
+
`find_view(bp, spider_payload)` is a way to grab a set of sub-views of a **controller** and return a listing of base-pointers to the **views**. Originally
|
3
|
+
designed to allow selection of sub-views during transition interceptors (hooks). This would usually upset the abstraction barrier between controllers, which
|
4
|
+
are not supposed to know about their children, but for practical and performance reasons, we have decided to go with this style of implementation.
|
5
|
+
|
6
|
+
A spider payload is a specially crafted cascading hash (usually created statically by macros) that represents a multi-branch view-hierarchy *regular* expression
|
7
|
+
that is able to capture views on it's way through traversal. It supports common operations of regular expressions such as *any* (`.`) and *one or more* (`+`) operator.
|
8
|
+
Thus, the spider payload is also able to select groups of views which is useful if you are doing a pushed view stack and need to know all except the top two views.
|
9
|
+
|
10
|
+
The following expressions are supported:
|
11
|
+
|
12
|
+
* `.+` - This means *at least one* view. It returns a group.
|
13
|
+
* `.` - This means *exactly one view*. It returns a single view.
|
14
|
+
* `my_view` - This is simply a named view.
|
15
|
+
|
16
|
+
Additionally, expressions may contain a *named* capture by adding a `:$NAME` to the expression:
|
17
|
+
|
18
|
+
* `.+:my_group`
|
19
|
+
* `.:my_view`
|
20
|
+
* `my_view:my_view`
|
21
|
+
|
22
|
+
An expression is then a selection tree:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
.
|
26
|
+
my_view
|
27
|
+
+
|
28
|
+
my_other_sub_view:content
|
29
|
+
my_other_view
|
30
|
+
```
|
31
|
+
|
32
|
+
> It is important to note that a selection will fail unless both all views in the selector are satisfied and that all views are satisfied have matching super-trees. In the above example, if there were two `my_view` descendents of our current controller we are selecting off, then `my_view` could not match half the selector on one descedent and then the other half on another descendent.
|
33
|
+
>
|
34
|
+
>
|
@@ -1,4 +1,15 @@
|
|
1
1
|
# Hooks in the kernel
|
2
2
|
|
3
3
|
## How user-generators work
|
4
|
-
As mentioned in the [User Handbook | Hooks](../user_handbook/hooks.md), user-generators are compiled into the kernel when the
|
4
|
+
As mentioned in the [User Handbook | Hooks](../user_handbook/hooks.md), user-generators are compiled into the kernel when the user
|
5
|
+
defines hooks in `./config/hooks.rb`. These hooks are then interpreted when the `flok` user binary runs through build process
|
6
|
+
via `UserHooksToManifestOrchestrator`. The orchestrator then evaluates the `./config/hooks.rb` through the `UserHooksDSL` which
|
7
|
+
captures each hook request as an unvalidated expression; that expression is then run through a generator block which yields
|
8
|
+
a hook manifest entry that can be added to the hooks manifest. The hooks compiler then takes the manifest and runs over the source
|
9
|
+
code with the manifest to inject code where needed.
|
10
|
+
|
11
|
+
## How hook entry points get placed in source
|
12
|
+
Hook entry points are not magical. They are hand placed, typically via ERB, into source as they require some JSON encoded data.
|
13
|
+
|
14
|
+
## Hook events
|
15
|
+
Hooks are emitted into user-space via the `hook` module [Hook](../mod/hooks.md).
|
data/docs/mod/controller.md
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
### Functions
|
7
7
|
`if_controller_init(bp, rvp, name, context)` - Initialize a controller that manages the view at `rvp` and contains the address `bp`. All events are sent to `bp` should be handled appropriatlely.
|
8
8
|
The `rvp` pointer will always be an initialized (but not attached) view. When receiving an action, the view is guaranteed to be attached at that time. Context is what the controller was initialized with.
|
9
|
+
**All controllers should be the same name as their views, there is a 1-1 relationship between views and controllers that was not originally true in the first version. Now views and contollers act as one**
|
9
10
|
|
10
11
|
### Spec helpers
|
11
12
|
|
@@ -28,8 +29,10 @@ special meanings based on the `name` field of the event:
|
|
28
29
|
but have not been destroyed.
|
29
30
|
|
30
31
|
### Spec fixtures (driver side)
|
31
|
-
There should be
|
32
|
+
There should be two identical controllers called `spec_one_spot` and `spec_blank` that can be initialized and should respond in the following ways when it receives an action and
|
32
33
|
event:
|
33
|
-
Note: an event is **not** a raw message, it is through the message of `int_event`, i.e. `[3,
|
34
|
+
Note: an event is **not** a raw message, it is through the message of `int_event`, i.e. `[3, $NAME, bp, "custom_event", info]`. The event name may either be `foo` or `bar`
|
34
35
|
Sends a **event** back called `action_rcv` containing `{from: from, to: to, info: info}` when an action is received
|
35
36
|
Sends a **event** back called `custom_rcv` containing a hash that looks like `{name: name, info: event}` when a custom event is received
|
37
|
+
|
38
|
+
Additionally, add a controller named `spec_blank_sends_context` that sends back the initialization context when it is created via the event named `context` with the initialization (context) parameters.
|
data/docs/mod/hook.md
CHANGED
@@ -4,6 +4,7 @@ The hook module allows the client to receive hook_event messages. This is a requ
|
|
4
4
|
###Driver messages
|
5
5
|
`if_hook_event(name, info)` - The name of the hook event and the information received.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
###Spec requirements
|
8
|
+
When built for spec testing, the client should have two hook handlers for the hook events named `test` and `test2`.
|
9
|
+
These hooks should both respond with a interrupt named `hook_dump_res` with the info `{name: "XXXX", info: info}`
|
10
|
+
where the name is either `test` or `test2` and the info is the received payload.
|
data/docs/mod/persist.md
CHANGED
data/docs/mod/ui.md
CHANGED
data/docs/user_handbook/hooks.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
##### There are two questions that *Hooks* were designed to solve.
|
5
5
|
|
6
6
|
1. Animation segues. When a controller switches actions, often time it is swapping out view controllers. Adding animations at this time would be the optimal time to do so. However, different clients, take blackberry and iOS, may either have fully-automated-animations, gesture controlled animations, cancelable-animations, synchronous-blocking, and the list goes on-and-on. Clearly, animations are handled differently on each platform, so how do we allow each platform to manage animation-segues?
|
7
|
-
2. There are times when a client, e.g.
|
7
|
+
2. There are times when a client, e.g. android, need to support semantics that are platform dependent. *For example*, you may need the back button on your mobile phone to trigger a view controller to go back a page. However, this semantic does not make much sense when you have multiple view controllers; e.g. *(What view controller receives the back clicked event?)*
|
8
8
|
|
9
9
|
##### Additionally, these questions must be solved with these constraints
|
10
10
|
1. Allowing the client to choose interception points at runtime would be prohibitively slow. Therefore, care should be taken to make sure hooks are as static as possible and do not add un-necessary runtime overhead.
|
@@ -12,12 +12,13 @@
|
|
12
12
|
-------
|
13
13
|
|
14
14
|
##### How hooks solves these problems:
|
15
|
-
*Hooks* solves these questions and constraitns by allowing the user to define triggers in their project under `./config/hooks.rb` using a *DSL* which
|
16
|
-
|
15
|
+
*Hooks* solves these questions and constraitns by allowing the user to define triggers in their project under `./config/hooks.rb` using a *DSL* which is used to create hook emitters at compile-time. These hook emitters send the hook notification to the client.
|
17
16
|
## Hooking by example with `./config/hooks.rb`
|
18
17
|
|
19
18
|
**Here is an example of a `./config/hooks.rb` which tells flok to notify the client that the `supports_back_clicked` hook triggered whenever a controller instance of a `"my_controller"` controller switches to an action via Goto that has an event handler defined with `back_clicked`:**
|
20
19
|
|
20
|
+
Here is an example of a hook configuration file with *one* hook. The hook generator is called `goto`, you may think of the generators as a set of helper DSL functions that have there own unique parameters. The first line, `hook :goto => :supports_back_clicked` denotes that we are using the `goto` generator and the emitted event is called `:supports_back_clicked`.
|
21
|
+
|
21
22
|
```ruby
|
22
23
|
# $USER_POJECT_ROOT/config/hooks.rb
|
23
24
|
hook :goto => :supports_back_clicked do
|
@@ -25,21 +26,31 @@ hook :goto => :supports_back_clicked do
|
|
25
26
|
to_action_responds_to? "back_clicked"
|
26
27
|
controller_name "my_controller"
|
27
28
|
|
28
|
-
#
|
29
|
-
|
29
|
+
#View hierarchy selectors
|
30
|
+
before_views({
|
31
|
+
"." => {
|
32
|
+
"__leaf__" => "foo"
|
33
|
+
}
|
34
|
+
})
|
30
35
|
end
|
31
36
|
```
|
32
37
|
|
33
|
-
|
38
|
+
A break down of this code is:
|
39
|
+
|
34
40
|
```ruby
|
35
|
-
hook :
|
36
|
-
#
|
41
|
+
hook :generator_name => :my_hook_name do
|
42
|
+
#Selectors To Hook on
|
43
|
+
|
44
|
+
#Various configuration
|
45
|
+
|
46
|
+
#View hierarchy to forward to hook
|
37
47
|
end
|
38
48
|
```
|
39
49
|
|
40
50
|
Selectors for each hook generator create more specific requirements for a trigger. By convention, all hook generators, if supplied no selector arguments will select all possible. **For example, this would hook all Goto statements in all controllers**:
|
51
|
+
|
41
52
|
```ruby
|
42
|
-
hook :
|
53
|
+
hook :goto => :all_goto do
|
43
54
|
end
|
44
55
|
```
|
45
56
|
|
@@ -47,7 +58,8 @@ end
|
|
47
58
|
---
|
48
59
|
The client, in-turn must handle the hook notification, in this example, the hook notification is named `supports_back_clicked`. The hook notifications typically includes a set of parameters, but the parameters are dependent on the *hook generator* used. In the above example, we are using the `goto` hook generator. See below for the different `hook generators` specifics.
|
49
60
|
|
50
|
-
|
61
|
+
See client docs for how to handle hook notifications, here is an example in pseudo code:
|
62
|
+
|
51
63
|
```ruby
|
52
64
|
handleHook("supports_back_clicked", function(hookInfo) {
|
53
65
|
var to_action_name = hookInfo.to_action_name;
|
@@ -61,6 +73,14 @@ handleHook("supports_back_clicked", function(hookInfo) {
|
|
61
73
|
* `to_action_responds_to? "event_name"` - Whenever a controller switches **to** an action that contains an `on "event_name", %{...}` handler
|
62
74
|
* `from_action_responds_to? "event_name"` - Whenever a controller switches **from** an action that contains an `on "event_name", %{...}` handler
|
63
75
|
* `controller "controller_name"` - Only applies to controllers with the name `"controller_name"`
|
76
|
+
* `Completion`
|
77
|
+
* The `completion` event is expected to be raised via `int_event` for all goto events. This is because the old view is not destroyed until the `completion` event is called
|
78
|
+
to allow you to use the view in animations.
|
79
|
+
* `Cancellation`:
|
80
|
+
* Unlike other semantics, `Goto` has issues with *cancellation* because the old views are destroyed. In order to work around this, you must call, after the completion
|
81
|
+
event, the `back` segue that you have described checking whether or not a transition was in progress (interactive) based on the view-controller itself.
|
82
|
+
* `info`:
|
83
|
+
* `ctp` - Completion telepointer, you should raise an `int_event` with this base-pointer.
|
64
84
|
|
65
85
|
## How the hook generators are defined & hooking internals
|
66
86
|
See [Kernel Handbook | Hooks](../kernel_handbook/hooks.md)
|
@@ -70,7 +90,7 @@ The user's `./config/hooks.rb` file is compiled and then evaluated statically to
|
|
70
90
|
and inserts code at particular hook detection points; the nature of the insertions is up to the particular hooking context.
|
71
91
|
|
72
92
|
##Synchronous vs Asynchronous Hooks
|
73
|
-
|
93
|
+
There are situations where you may want a synchronous hook. Examples include
|
74
94
|
|
75
95
|
##Hooking check points
|
76
96
|
Each controller has a plethora of functions that determine it's lifetime and behaviours. These functions include the actions of creation, destruction, embedding, pushing actions, talking to services, etc.
|
@@ -83,14 +103,18 @@ the following JSON format:
|
|
83
103
|
The name is the hook name and the params is context specific inforamtion the compiler has embedded. Live variables that are in the context of the hook detection point are described in each hook detection point below.
|
84
104
|
|
85
105
|
* `controller_will_goto` - The controller is about to invoke the Goto macro and switch actions or it has just entered the first action from choose_action (which is a Goto).
|
86
|
-
* params (static generated)
|
106
|
+
* params (static generated in the hook info)
|
87
107
|
* `controller_name` - The controller name that this entry effects
|
88
108
|
* `from_action` - The name of the action we are coming from
|
89
109
|
* `to_action` - The name of the action we are going to
|
90
|
-
* Useful (dynamic) variables
|
110
|
+
* Useful (dynamic/local JS) variables
|
91
111
|
* `old_action` - The previous action, equal to `from_action` but in dynamic form. If there is no action, this is set to `choose_action`. Not sure why you would use this
|
92
112
|
* `__info__.action` - The name of the new action
|
93
|
-
*
|
113
|
+
* `controller_did_goto` - The controller has completed the goto switch
|
114
|
+
* params (static)
|
115
|
+
* `controller_name` - The controller name that this entry effects
|
116
|
+
* `from_action` - The name of the action we are coming from
|
117
|
+
* `to_action` - The name of the action we are going to
|
94
118
|
|
95
119
|
##Hooks Compiler
|
96
120
|
The hooks compiler is able to take the hook entry points and inject code into them via a set of `HooksManifestEntries` which are bound togeather via a `HooksManifest`. The actual
|
data/flok.gemspec
CHANGED
@@ -34,6 +34,8 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_runtime_dependency "rake", "~> 10.3"
|
35
35
|
spec.add_runtime_dependency 'naturalsort', "~> 1.0"
|
36
36
|
spec.add_runtime_dependency 'awesome_print', "~> 1.6"
|
37
|
+
spec.add_runtime_dependency 'file-tail', "~> 1.1"
|
37
38
|
spec.add_development_dependency "therubyracer", "~> 0.12"
|
39
|
+
spec.add_runtime_dependency "xcpretty", "~> 0.2"
|
38
40
|
spec.executables << 'flok'
|
39
41
|
end
|
data/lib/flok/user_compiler.rb
CHANGED
@@ -183,15 +183,29 @@ module Flok
|
|
183
183
|
var old_action = __info__.action;
|
184
184
|
__info__.action = "#{action_name}";
|
185
185
|
|
186
|
+
var __free_asap = true;
|
186
187
|
//HOOK_ENTRY[controller_will_goto] #{{"controller_name" => @controller.name, "might_respond_to" => @ctx.might_respond_to, "actions_responds_to" => @ctx.actions_respond_to, "from_action" => @name, "to_action" => action_name}.to_json}
|
187
188
|
|
189
|
+
//If views are configured to not free right away, set up a new stack of views to free
|
190
|
+
//This is usually picked up by the hook GOTO
|
191
|
+
if (__free_asap === false) {
|
192
|
+
var views_to_free_id = gen_id();
|
193
|
+
views_to_free[views_to_free_id] = views_to_free[views_to_free_id] || [];
|
194
|
+
}
|
195
|
+
|
188
196
|
//Remove all views, we don't have to recurse because removal of a view
|
189
197
|
//is supposed to remove *all* view controllers of that tree as well.
|
190
198
|
var embeds = __info__.embeds;
|
191
199
|
for (var i = 0; i < __info__.embeds.length; ++i) {
|
192
200
|
for (var j = 0; j < __info__.embeds[i].length; ++j) {
|
193
201
|
//Free +1 because that will be the 'main' view
|
194
|
-
|
202
|
+
|
203
|
+
//Free if 'free_asap' is not set, this is usually configured via the 'goto' hook
|
204
|
+
if (__free_asap === true) {
|
205
|
+
main_q.push([1, "if_free_view", embeds[i][j]+1]);
|
206
|
+
} else {
|
207
|
+
views_to_free[views_to_free_id].push(embeds[i][j]+1);
|
208
|
+
}
|
195
209
|
|
196
210
|
//Call dealloc on the controller
|
197
211
|
tel_deref(embeds[i][j]).cte.__dealloc__(embeds[i][j]);
|
@@ -223,6 +237,7 @@ module Flok
|
|
223
237
|
//located in ctable
|
224
238
|
__info__.cte.actions[__info__.action].on_entry(__base__)
|
225
239
|
|
240
|
+
//HOOK_ENTRY[controller_did_goto] #{{"controller_name" => @controller.name, "might_respond_to" => @ctx.might_respond_to, "actions_responds_to" => @ctx.actions_respond_to, "from_action" => @name, "to_action" => action_name}.to_json}
|
226
241
|
//'choose_action' pseudo-action will be sent as 'null' as it's the initial state
|
227
242
|
if (old_action === "choose_action") {
|
228
243
|
old_action = null;
|
@@ -233,6 +248,7 @@ module Flok
|
|
233
248
|
from: old_action,
|
234
249
|
to: "#{action_name}"
|
235
250
|
}]);
|
251
|
+
|
236
252
|
}
|
237
253
|
out.puts res
|
238
254
|
elsif l =~ /Push/
|
@@ -589,7 +605,7 @@ module Flok
|
|
589
605
|
self.instance_eval(¯o)
|
590
606
|
@current_action = nil
|
591
607
|
else
|
592
|
-
raise "No macro found named: #{method}"
|
608
|
+
raise "No macro found named: #{method} for controller #{@controller.name} in action #{@name}"
|
593
609
|
end
|
594
610
|
end
|
595
611
|
end
|
@@ -2,10 +2,12 @@ require_relative 'helpers'
|
|
2
2
|
|
3
3
|
module Flok
|
4
4
|
class GotoHooksDSLEnv
|
5
|
-
attr_accessor :selectors
|
5
|
+
attr_accessor :selectors, :before_view_spider, :after_view_spider
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@selectors = []
|
9
|
+
@before_view_spider = {}
|
10
|
+
@after_view_spider = {}
|
9
11
|
end
|
10
12
|
|
11
13
|
def controller name
|
@@ -50,6 +52,14 @@ module Flok
|
|
50
52
|
end
|
51
53
|
end
|
52
54
|
#################################################################################
|
55
|
+
|
56
|
+
def before_views spider
|
57
|
+
@before_view_spider = spider
|
58
|
+
end
|
59
|
+
|
60
|
+
def after_views spider
|
61
|
+
@after_view_spider = spider
|
62
|
+
end
|
53
63
|
end
|
54
64
|
|
55
65
|
UserHooksToManifestOrchestrator.register_hook_gen :goto do |manifest, params|
|
@@ -61,14 +71,32 @@ module Flok
|
|
61
71
|
dsl_env = GotoHooksDSLEnv.new
|
62
72
|
dsl_env.instance_eval(&block)
|
63
73
|
|
74
|
+
ns = "_#{SecureRandom.hex[0..5]}"
|
75
|
+
|
64
76
|
#Inject into HOOK_ENTRY[controller_will_goto] that match the given selectors from the DSL
|
65
77
|
#based on the hook entry static parameters
|
66
|
-
|
78
|
+
manifest << HooksManifestEntry.new("controller_will_goto", dsl_env.selectors) do |entry_hook_params|
|
67
79
|
next %{
|
68
|
-
|
80
|
+
var #{ns}_before_views = find_view(__base__, #{dsl_env.before_view_spider.to_json});
|
81
|
+
__free_asap = false;
|
69
82
|
}
|
70
83
|
end
|
71
84
|
|
72
|
-
manifest <<
|
85
|
+
manifest << HooksManifestEntry.new("controller_did_goto", dsl_env.selectors) do |entry_hook_params|
|
86
|
+
next %{
|
87
|
+
//The completion callback will share a pointer to the views_to_free key index
|
88
|
+
reg_evt(views_to_free_id, hook_goto_completion_cb);
|
89
|
+
|
90
|
+
var #{ns}_after_views = find_view(__base__, #{dsl_env.after_view_spider.to_json});
|
91
|
+
var #{ns}_info = {
|
92
|
+
views: #{ns}_after_views,
|
93
|
+
cep: views_to_free_id
|
94
|
+
};
|
95
|
+
for (var k in #{ns}_before_views) {
|
96
|
+
#{ns}_info.views[k] = #{ns}_before_views[k];
|
97
|
+
}
|
98
|
+
SEND("main", "if_hook_event", "#{hook_event_name}", #{ns}_info);
|
99
|
+
}
|
100
|
+
end
|
73
101
|
end
|
74
102
|
end
|
data/lib/flok/version.rb
CHANGED
data/spec/env/iface.rb
CHANGED
@@ -27,6 +27,10 @@ shared_context "iface:driver" do
|
|
27
27
|
include SpecHelpers
|
28
28
|
before(:each) do
|
29
29
|
@pipe = IO.popen("rake pipe:driver", "r+")
|
30
|
+
wait_for_load = @pipe.readline
|
31
|
+
$stderr.puts "waiting for LOADED from pipe"
|
32
|
+
raise "Your pipe should have emitted LOADED at the start when it was ready, instead got #{wait_for_load.inspect}" if wait_for_load.strip != "LOADED"
|
33
|
+
$stderr.puts "got LOADED from pipe"
|
30
34
|
@pid = @pipe.pid
|
31
35
|
@mods = Flok::Platform.mods ENV['FLOK_ENV']
|
32
36
|
end
|
@@ -47,6 +51,10 @@ def mods
|
|
47
51
|
Flok::Platform.mods ENV['FLOK_ENV']
|
48
52
|
end
|
49
53
|
|
54
|
+
def defines
|
55
|
+
Flok::Platform.defines ENV['FLOK_ENV']
|
56
|
+
end
|
57
|
+
|
50
58
|
def config_yml
|
51
59
|
Flok::Platform.config_yml ENV['FLOK_ENV']
|
52
60
|
end
|
@@ -58,6 +66,20 @@ def module_dep name
|
|
58
66
|
end
|
59
67
|
end
|
60
68
|
|
69
|
+
#Similar to module_dep this checks for a defines as well, useful for optional specs
|
70
|
+
def module_dep_defines(name:, defines:)
|
71
|
+
before(:each) do
|
72
|
+
if mods.include? name
|
73
|
+
unless (Flok::Platform.defines ENV["FLOK_ENV"])[defines]
|
74
|
+
skip "#{ENV["PLATFORM"].inspect} does support #{name.inspect} module but does not define #{defines} in config.yml"
|
75
|
+
end
|
76
|
+
else
|
77
|
+
skip "#{ENV["PLATFORM"].inspect} does not support #{name.inspect} module in config.yml"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
61
83
|
#Require a key value to be a apart of the config yml
|
62
84
|
def settings_dep key, value
|
63
85
|
raise "#{ENV["PLATFORM"].inspect} does not support #{key.inspect} configuration in config.yml" unless config_yml.include? key
|
@@ -78,3 +100,19 @@ def restart_driver_but_persist
|
|
78
100
|
raise "Tried to restart driver but timed out waiting for 'RESTART OK'"
|
79
101
|
end
|
80
102
|
end
|
103
|
+
|
104
|
+
#Do not persist
|
105
|
+
def hard_restart_driver
|
106
|
+
#Ensure the pipe is fully drained before sending RESTART
|
107
|
+
@pipe.puts [[0, 0, "ping"]].to_json; @pipe.readline_timeout
|
108
|
+
|
109
|
+
@pipe.puts "HARD_RESTART"
|
110
|
+
begin
|
111
|
+
Timeout::timeout(10) do
|
112
|
+
expect(@pipe.readline).to eq("RESTART OK\n")
|
113
|
+
end
|
114
|
+
rescue Timeout::Error
|
115
|
+
raise "Tried to HARD restart driver but timed out waiting for 'RESTART OK'"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
data/spec/env/kern.rb
CHANGED
@@ -177,9 +177,13 @@ shared_context "kern" do
|
|
177
177
|
#for non-existant messages
|
178
178
|
def ignore_up_to msg_name, priority=nil, &block
|
179
179
|
@did_get = []
|
180
|
+
@original_q = @q == nil ? nil : JSON.parse(@q.to_json)
|
181
|
+
@original_cq = @cq == nil ? nil : JSON.parse(@cq.to_json)
|
180
182
|
|
181
183
|
loop do
|
182
184
|
if @q.count == 0 and @cq.count == 0
|
185
|
+
@q = @original_q
|
186
|
+
@cq = @original_cq
|
183
187
|
raise "Waited for the message #{msg_name.inspect} but never got it... did get: \n * #{@did_get.join("\n * ")}"
|
184
188
|
end
|
185
189
|
#Dequeue from multi-priority queue if possible
|
@@ -16,18 +16,18 @@ RSpec.describe "iface:driver:controller" do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
#Create a controller with the given base pointer and attach view to a spot pointer (rspace)
|
19
|
-
def init_controller(bp, view_name="spec_blank", rspace=0)
|
19
|
+
def init_controller(bp, view_name="spec_blank", rspace=0, context={})
|
20
20
|
#Views are always bp+1, the bp points to an array with ['vc', 'main', spots...]
|
21
21
|
# bp bp+1 bp+n
|
22
22
|
#Create a new view 'spec_blank' at bp+1
|
23
|
-
if view_name == "spec_blank"
|
23
|
+
if view_name == "spec_blank" || view_name == "spec_blank_sends_context"
|
24
24
|
@pipe.puts [[0, 4, "if_init_view", view_name, {}, bp+1, ["main"]]].to_json
|
25
25
|
elsif view_name == "spec_one_spot"
|
26
26
|
@pipe.puts [[0, 4, "if_init_view", view_name, {}, bp+1, ["main", "content"]]].to_json
|
27
27
|
end
|
28
28
|
|
29
29
|
#Initilaize the view controller
|
30
|
-
@pipe.puts [[0, 4, "if_controller_init", bp, bp+1,
|
30
|
+
@pipe.puts [[0, 4, "if_controller_init", bp, bp+1, view_name, context]].to_json
|
31
31
|
|
32
32
|
#Attach that view to the root
|
33
33
|
@pipe.puts [[0, 2, "if_attach_view", bp+1, rspace]].to_json
|
@@ -57,17 +57,36 @@ RSpec.describe "iface:driver:controller" do
|
|
57
57
|
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([3, "int_event", bp, "action_rcv", {"from" => nil, "to" => to_action}], 6.seconds)
|
58
58
|
end
|
59
59
|
|
60
|
-
it "Does send back a message for the test controller custom action" do
|
60
|
+
it "Does send back a message for the test controller custom action named 'foo'" do
|
61
61
|
bp = 332
|
62
62
|
init_controller(bp)
|
63
63
|
|
64
64
|
#Send an action event
|
65
|
-
custom_name =
|
65
|
+
custom_name = "foo"
|
66
66
|
custom_info = {"info" => SecureRandom.hex}
|
67
67
|
send_event(bp, custom_name, custom_info)
|
68
68
|
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([3, "int_event", bp, "custom_rcv", {"name" => custom_name, "info" => custom_info}], 6.seconds)
|
69
69
|
end
|
70
70
|
|
71
|
+
it "Does send back a message for the test controller custom action named 'bar'" do
|
72
|
+
bp = 332
|
73
|
+
init_controller(bp)
|
74
|
+
|
75
|
+
#Send an action event
|
76
|
+
custom_name = "bar"
|
77
|
+
custom_info = {"info" => SecureRandom.hex}
|
78
|
+
send_event(bp, custom_name, custom_info)
|
79
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([3, "int_event", bp, "custom_rcv", {"name" => custom_name, "info" => custom_info}], 6.seconds)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "Does receive the context on initialization" do
|
83
|
+
bp = 332
|
84
|
+
init_controller(bp, "spec_blank_sends_context", 0, {"foo" => "bar"})
|
85
|
+
|
86
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([3, "int_event", bp, "context", {"foo" => "bar"}], 6.seconds)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
71
90
|
it "When a view is deleted that was associated with a view controller, the view controller should no longer exist" do
|
72
91
|
bp = 332
|
73
92
|
init_controller(bp)
|
@@ -91,7 +110,7 @@ RSpec.describe "iface:driver:controller" do
|
|
91
110
|
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([1, "spec", [bp0, bp1]], 6.seconds)
|
92
111
|
end
|
93
112
|
|
94
|
-
it "Can initialize a controller that embeds a controller and delete all
|
113
|
+
it "Can initialize a controller that embeds a controller and delete all sub-controllers when a parent view is destroyed" do
|
95
114
|
bp0 = 332
|
96
115
|
bp1 = 335
|
97
116
|
init_controller(bp0, "spec_one_spot")
|