durable_rules 0.34.27 → 0.34.28

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8271032dff0a76d7a23894c8feac51fd816be8f
4
- data.tar.gz: 565c32ae6735f76c0e732ebd28fc63fec5959ef3
3
+ metadata.gz: 444692ec85550db95da9c6f15a8a4a28a5595327
4
+ data.tar.gz: f5613ee7347ce15f9f155a0819ff78463a842d06
5
5
  SHA512:
6
- metadata.gz: 9bf826e66598b81e9de27aa890957132dd63cd3687ca46e9fe78c2b2e4dac178fc026173f4fae4ed73d285484c3b1cb6d65ed649ee32f24fe43b13093ef64471
7
- data.tar.gz: ec3ccd64ea46ec1ead3bda34a917d0865661c8aff9a245547ec8d03ac220907a160d55fea4464692670c131bff130411308b68a7a073bbd7a105d7b39fd6c2cb
6
+ metadata.gz: 00fb2a9657488183693516eae86078b46c22c1639c9c684c605e44a9c73b6a04d09581f116f637a9d8ce8b21c5931f4fbd20df0f40f90c1bf46a8280521e5362
7
+ data.tar.gz: 2032f03a299f12291099f33f1adec895ed3f67aec3a0b0e14ec1bf90b8f9bc32ad2b340ca140ce403e3b4f5d3fdf66002efc57e128af7a43c8a620a8dcd91739
@@ -141,6 +141,10 @@ module Durable
141
141
  return Expression.new(@name, @left).matches(other)
142
142
  end
143
143
 
144
+ def imatches(other)
145
+ return Expression.new(@name, @left).imatches(other)
146
+ end
147
+
144
148
  def ref_id(sid)
145
149
  Arithmetic.new @name, @left, sid
146
150
  end
@@ -251,6 +255,12 @@ module Durable
251
255
  self
252
256
  end
253
257
 
258
+ def imatches(other)
259
+ @__op = :$imt
260
+ @right = other
261
+ self
262
+ end
263
+
254
264
  def -@
255
265
  @__op = :$nex
256
266
  @right = 1
@@ -424,10 +434,6 @@ module Durable
424
434
  {:pri => value}
425
435
  end
426
436
 
427
- def span(value)
428
- {:span => value}
429
- end
430
-
431
437
  def cap(value)
432
438
  {:cap => value}
433
439
  end
@@ -482,10 +488,6 @@ module Durable
482
488
  rule["pri"] = options[:pri]
483
489
  end
484
490
 
485
- if options.key? :span
486
- rule["span"] = options[:span]
487
- end
488
-
489
491
  if options.key? :cap
490
492
  rule["cap"] = options[:cap]
491
493
  end
@@ -124,29 +124,38 @@ module Engine
124
124
  @_queues[ruleset_name]
125
125
  end
126
126
 
127
- def start_timer(timer_name, duration, timer_id = nil)
128
- if !timer_id
129
- timer_id = timer_name
127
+ def start_timer(timer_name, duration, manual_reset = false)
128
+ if manual_reset
129
+ manual_reset = 1
130
+ else
131
+ manual_reset = 0
130
132
  end
131
133
 
132
- if @_timers.key? timer_id
133
- raise ArgumentError, "Timer with id #{timer_id} already added"
134
+ if @_timers.key? timer_name
135
+ raise ArgumentError, "Timer with name #{timer_name} already added"
134
136
  else
135
- timer = {:sid => @s.sid, :id => timer_id, :$t => timer_name}
136
- @_timers[timer_id] = [timer, duration]
137
+ timer = {:sid => @s.sid, :$t => timer_name}
138
+ @_timers[timer_id] = [timer, duration, manual_reset]
137
139
  end
138
140
  end
139
141
 
140
- def cancel_timer(timer_name, timer_id = nil)
141
- if !timer_id
142
- timer_id = timer_name
142
+ def cancel_timer(timer_name)
143
+ if @_cancelled_timers.key? timer_name
144
+ raise ArgumentError, "Timer with id #{timer_name} already cancelled"
145
+ else
146
+ @_cancelled_timers[timer_name] = true
143
147
  end
148
+ end
144
149
 
145
- if @_cancelled_timers.key? timer_id
146
- raise ArgumentError, "Timer with id #{timer_id} already cancelled"
150
+ def reset_timer(timer_name)
151
+ if @m.kind_of? Hash
152
+ retract_timer timer_name, @m
147
153
  else
148
- timer = {:sid => @s.sid, :id => timer_id, :$t => timer_name}
149
- @_cancelled_timers[timer_id] = timer
154
+ for m in @m do
155
+ return true if retract_timer(timer_name, m)
156
+ end
157
+
158
+ return false
150
159
  end
151
160
  end
152
161
 
@@ -214,6 +223,22 @@ module Engine
214
223
 
215
224
  private
216
225
 
226
+ def retract_timer(timer_name, message)
227
+ if ((message.key? :$t) && (message[:$t] == timer_name)) ||
228
+ ((message.key? '$t') && (message['$t'] == timer_name))
229
+ retract(message)
230
+ return true
231
+ end
232
+
233
+ for property_name, property_value in message do
234
+ if (property_value.kind_of? Hash) && retract_timer(timer_name, property_value)
235
+ return true
236
+ end
237
+ end
238
+
239
+ return false
240
+ end
241
+
217
242
  def handle_property(name, value=nil)
218
243
  name = name.to_s
219
244
  if name.end_with? '?'
@@ -369,11 +394,10 @@ module Engine
369
394
  end
370
395
  end
371
396
 
372
- id = rand(1000000000)
373
397
  if assert_state
374
- c.assert(:label => to_state, :chart => 1, :id => id)
398
+ c.assert(:label => to_state, :chart => 1)
375
399
  else
376
- c.post(:label => to_state, :chart => 1, :id => id)
400
+ c.post(:label => to_state, :chart => 1)
377
401
  end
378
402
  end
379
403
  }
@@ -453,12 +477,12 @@ module Engine
453
477
  Rules.start_assert_events @handle, JSON.generate(messages)
454
478
  end
455
479
 
456
- def start_timer(sid, timer, timer_duration)
457
- Rules.start_timer @handle, sid.to_s, timer_duration, JSON.generate(timer)
480
+ def start_timer(sid, timer, timer_duration, manual_reset)
481
+ Rules.start_timer @handle, sid.to_s, timer_duration, manual_reset, JSON.generate(timer)
458
482
  end
459
483
 
460
- def cancel_timer(sid, timer)
461
- Rules.cancel_timer @handle, sid.to_s, JSON.generate(timer)
484
+ def cancel_timer(sid, timer_name)
485
+ Rules.cancel_timer @handle, sid.to_s, timer_name.to_s
462
486
  end
463
487
 
464
488
  def assert_fact(fact)
@@ -608,12 +632,12 @@ module Engine
608
632
  complete.call e, true
609
633
  else
610
634
  begin
611
- for timer_id, timer in c._cancelled_timers do
612
- cancel_timer c.s.sid, timer
635
+ for timer_name, timer_value in c._cancelled_timers do
636
+ cancel_timer c.s.sid, timer_name
613
637
  end
614
638
 
615
- for timer_id, timer_duration in c._timers do
616
- start_timer c.s.sid, timer_duration[0], timer_duration[1]
639
+ for timer_id, timer_tuple in c._timers do
640
+ start_timer c.s.sid, timer_tuple[0], timer_tuple[1], timer_tuple[2]
617
641
  end
618
642
 
619
643
  for ruleset_name, q in c._queues do
@@ -752,8 +776,7 @@ module Engine
752
776
  if ((trigger.key? :to) && (trigger[:to] == state_name)) ||
753
777
  ((trigger.key? "to") && (trigger["to"] == state_name)) ||
754
778
  (trigger.key? :count) || (trigger.key? "count") ||
755
- (trigger.key? :cap) || (trigger.key? "cap") ||
756
- (trigger.key? :span) || (trigger.key? "span")
779
+ (trigger.key? :cap) || (trigger.key? "cap")
757
780
  reflexive_states[qualified_name] = true
758
781
  end
759
782
  end
@@ -807,12 +830,6 @@ module Engine
807
830
  rule[:count] = trigger["count"]
808
831
  end
809
832
 
810
- if trigger.key? :span
811
- rule[:span] = trigger[:span]
812
- elsif trigger.key? "span"
813
- rule[:span] = trigger["span"]
814
- end
815
-
816
833
  if trigger.key? :cap
817
834
  rule[:cap] = trigger[:cap]
818
835
  elsif trigger.key? "cap"
@@ -936,8 +953,7 @@ module Engine
936
953
  for transition_name, transition in stage_to do
937
954
  if (transition_name == stage_name) ||
938
955
  (transition.key? :count) || (transition.key? "count") ||
939
- (transition.key? :cap) || (transition.key? "cap") ||
940
- (transition.key? :span) || (transition.key? "span")
956
+ (transition.key? :cap) || (transition.key? "cap")
941
957
  reflexive_stages[stage_name] = true
942
958
  end
943
959
  end
@@ -1002,12 +1018,6 @@ module Engine
1002
1018
  rule[:count] = transition["count"]
1003
1019
  end
1004
1020
 
1005
- if transition.key? :span
1006
- rule[:span] = transition[:span]
1007
- elsif transition.key? "span"
1008
- rule[:span] = transition["span"]
1009
- end
1010
-
1011
1021
  if transition.key? :cap
1012
1022
  rule[:cap] = transition[:cap]
1013
1023
  elsif transition.key? "cap"
@@ -77,7 +77,7 @@ module Interface
77
77
  end
78
78
  end
79
79
 
80
- post "/:ruleset_name/fact/:sid" do
80
+ post "/:ruleset_name/facts/:sid" do
81
81
  begin
82
82
  request.body.rewind
83
83
  message = JSON.parse request.body.read
@@ -39,6 +39,7 @@
39
39
  #define OP_STRING_STRING 0x0101
40
40
  #define OP_STRING_NIL 0x0107
41
41
  #define OP_STRING_REGEX 0x010C
42
+ #define OP_STRING_IREGEX 0x010D
42
43
  #define OP_NIL_BOOL 0x0704
43
44
  #define OP_NIL_INT 0x0702
44
45
  #define OP_NIL_DOUBLE 0x0703
@@ -885,9 +886,11 @@ static unsigned int isMatch(ruleset *tree,
885
886
 
886
887
  break;
887
888
  case OP_STRING_REGEX:
889
+ case OP_STRING_IREGEX:
888
890
  *propertyMatch = evaluateRegex(tree,
889
891
  message + currentProperty->valueOffset,
890
892
  currentProperty->valueLength,
893
+ (type == OP_STRING_REGEX) ? 0 : 1,
891
894
  currentAlpha->right.value.regex.vocabularyLength,
892
895
  currentAlpha->right.value.regex.statesLength,
893
896
  currentAlpha->right.value.regex.stateMachineOffset);
@@ -1878,7 +1881,7 @@ unsigned int queueMessage(void *handle, unsigned int queueAction, char *sid, cha
1878
1881
  return registerMessage(rulesBinding, queueAction, destination, message);
1879
1882
  }
1880
1883
 
1881
- unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *timer) {
1884
+ unsigned int startTimer(void *handle, char *sid, unsigned int duration, char manualReset, char *timer) {
1882
1885
  void *rulesBinding;
1883
1886
  if (!sid) {
1884
1887
  sid = "0";
@@ -1889,10 +1892,10 @@ unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *ti
1889
1892
  return result;
1890
1893
  }
1891
1894
 
1892
- return registerTimer(rulesBinding, duration, timer);
1895
+ return registerTimer(rulesBinding, duration, manualReset, timer);
1893
1896
  }
1894
1897
 
1895
- unsigned int cancelTimer(void *handle, char *sid, char *timer) {
1898
+ unsigned int cancelTimer(void *handle, char *sid, char *timerName) {
1896
1899
  void *rulesBinding;
1897
1900
  if (!sid) {
1898
1901
  sid = "0";
@@ -1903,7 +1906,7 @@ unsigned int cancelTimer(void *handle, char *sid, char *timer) {
1903
1906
  return result;
1904
1907
  }
1905
1908
 
1906
- return removeTimer(rulesBinding, timer);
1909
+ return removeTimer(rulesBinding, timerName);
1907
1910
  }
1908
1911
 
1909
1912
  unsigned int renewActionLease(void *handle, char *sid) {
@@ -15,6 +15,7 @@
15
15
  #define JSON_STATE_IDIOM 0x0A
16
16
  #define JSON_EVENT_IDIOM 0x0B
17
17
  #define JSON_REGEX 0x0C
18
+ #define JSON_IREGEX 0x0D
18
19
 
19
20
  unsigned int readNextName(char *start, char **first, char **last, unsigned int *hash);
20
21
  unsigned int readNextValue(char *start, char **first, char **last, unsigned char *type);
@@ -393,16 +393,8 @@ static unsigned int loadRemoveActionCommand(ruleset *tree, binding *rulesBinding
393
393
  "local delete_frame = function(key, action_key)\n"
394
394
  " local rule_action_key = redis.call(\"lpop\", key)\n"
395
395
  " local raw_count = redis.call(\"lpop\", key)\n"
396
- " local count = 1\n"
397
- " if raw_count ~= \"single\" then\n"
398
- " count = tonumber(raw_count)\n"
399
- " end\n"
400
- " if count == 0 then\n"
401
- " local packed_frame = redis.call(\"lpop\", rule_action_key)\n"
402
- " while packed_frame ~= \"0\" do\n"
403
- " packed_frame = redis.call(\"lpop\", rule_action_key)\n"
404
- " end\n"
405
- " else\n"
396
+ " if raw_count then"
397
+ " local count = tonumber(string.sub(raw_count, 3))\n"
406
398
  " for i = 0, count - 1, 1 do\n"
407
399
  " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
408
400
  " end\n"
@@ -439,12 +431,10 @@ static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding) {
439
431
  "local timestamp = tonumber(ARGV[1])\n"
440
432
  "local res = redis.call(\"zrangebyscore\", timer_key, 0, timestamp, \"limit\", 0, 50)\n"
441
433
  "if #res > 0 then\n"
442
- " for i = 0, #res, 1 do\n"
443
- " if res[i] then\n"
444
- " redis.call(\"zincrby\", timer_key, 10, tostring(res[i]))\n"
434
+ " for i = 1, #res, 1 do\n"
435
+ " redis.call(\"zincrby\", timer_key, 10, tostring(res[i]))\n"
445
436
  " end\n"
446
- " end\n"
447
- " return res\n"
437
+ " return res\n"
448
438
  "end\n"
449
439
  "return 0\n", name) == -1) {
450
440
  return ERR_OUT_OF_MEMORY;
@@ -460,6 +450,34 @@ static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding) {
460
450
  return RULES_OK;
461
451
  }
462
452
 
453
+ static unsigned int loadRemoveTimerCommand(ruleset *tree, binding *rulesBinding) {
454
+ char *name = &tree->stringPool[tree->nameOffset];
455
+ redisContext *reContext = rulesBinding->reContext;
456
+ redisReply *reply;
457
+ char *lua = NULL;
458
+ if (asprintf(&lua,
459
+ "local timer_key = \"%s!t\"\n"
460
+ "local timer_name = ARGV[1]\n"
461
+ "local res = redis.call(\"zrange\", timer_key, 0, -1)\n"
462
+ "for i = 1, #res, 1 do\n"
463
+ " if string.find(res[i], \"\\\"%%$t\\\"%%s*:%%s*\\\"\" .. timer_name .. \"\\\"\") then\n"
464
+ " redis.call(\"zrem\", timer_key, res[i])\n"
465
+ " end\n"
466
+ "end\n"
467
+ "return 0\n", name) == -1) {
468
+ return ERR_OUT_OF_MEMORY;
469
+ }
470
+
471
+ unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
472
+ GET_REPLY(result, "loadRemoveTimerCommand", reply);
473
+
474
+ strncpy(rulesBinding->removeTimerHash, reply->str, 40);
475
+ rulesBinding->removeTimerHash[40] = '\0';
476
+ freeReplyObject(reply);
477
+ free(lua);
478
+ return RULES_OK;
479
+ }
480
+
463
481
  static unsigned int loadUpdateActionCommand(ruleset *tree, binding *rulesBinding) {
464
482
  char *name = &tree->stringPool[tree->nameOffset];
465
483
  redisContext *reContext = rulesBinding->reContext;
@@ -559,6 +577,7 @@ static unsigned int loadDeleteSessionCommand(ruleset *tree, binding *rulesBindin
559
577
  " redis.call(\"del\", all_keys[i])\n"
560
578
  " end\n"
561
579
  "end\n"
580
+ "redis.call(\"hdel\", \"%s!c\", sid)\n"
562
581
  "redis.call(\"hdel\", \"%s!s\", sid)\n"
563
582
  "redis.call(\"hdel\", \"%s!s!v\", sid)\n"
564
583
  "redis.call(\"zrem\", \"%s!a\", sid)\n"
@@ -569,6 +588,7 @@ static unsigned int loadDeleteSessionCommand(ruleset *tree, binding *rulesBindin
569
588
  name,
570
589
  name,
571
590
  name,
591
+ name,
572
592
  name,
573
593
  name,
574
594
  name,
@@ -1031,54 +1051,31 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1031
1051
  "local load_frame_from_rule = function(rule_action_key, raw_count, sid, max_score)\n"
1032
1052
  " local frames = {}\n"
1033
1053
  " local packed_frames = {}\n"
1034
- " local unwrap = true\n"
1035
- " local count = 1\n"
1036
- " local left = false\n"
1037
- " if raw_count ~= \"single\" then\n"
1038
- " count = tonumber(raw_count)\n"
1039
- " unwrap = false\n"
1040
- " end\n"
1041
- " if count == 0 then\n"
1042
- " left = true\n"
1043
- " local packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1044
- " while packed_frame ~= \"0\" do\n"
1054
+ " local count = tonumber(string.sub(raw_count, 3))\n"
1055
+ " local window = false\n"
1056
+ " if string.find(raw_count, \"$w\") == 1 then\n"
1057
+ " window = true\n"
1058
+ " end\n"
1059
+ " for i = 0, count - 1, 1 do\n"
1060
+ " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
1061
+ " if not packed_frame then\n"
1062
+ " break\n"
1063
+ " else\n"
1045
1064
  " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1046
1065
  " if frame then\n"
1047
1066
  " table.insert(frames, frame)\n"
1048
1067
  " table.insert(packed_frames, packed_frame)\n"
1049
1068
  " end\n"
1050
- " packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1051
- " end\n"
1052
- " if #packed_frames > 0 then\n"
1053
- " redis.call(\"lpush\", rule_action_key, 0)\n"
1054
- " end\n"
1055
- " else\n"
1056
- " while count > 0 do\n"
1057
- " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
1058
- " if not packed_frame then\n"
1059
- " break\n"
1060
- " else\n"
1061
- " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1062
- " if frame then\n"
1063
- " table.insert(frames, frame)\n"
1064
- " table.insert(packed_frames, packed_frame)\n"
1065
- " count = count - 1\n"
1066
- " end\n"
1067
- " end\n"
1068
1069
  " end\n"
1069
1070
  " end\n"
1070
1071
  " for i = #packed_frames, 1, -1 do\n"
1071
- " if left then\n"
1072
- " redis.call(\"lpush\", rule_action_key, packed_frames[i])\n"
1073
- " else\n"
1074
- " redis.call(\"rpush\", rule_action_key, packed_frames[i])\n"
1075
- " end\n"
1072
+ " redis.call(\"rpush\", rule_action_key, packed_frames[i])\n"
1076
1073
  " end\n"
1077
- " if #packed_frames == 0 then\n"
1074
+ " if #packed_frames == 0 or (window and (#packed_frames ~= count)) then\n"
1078
1075
  " return nil, nil\n"
1079
1076
  " end\n"
1080
1077
  " local last_name = string.find(rule_action_key, \"!\") - 1\n"
1081
- " if unwrap then\n"
1078
+ " if window and count == 1 then\n"
1082
1079
  " return string.sub(rule_action_key, 1, last_name), frames[1]\n"
1083
1080
  " else\n"
1084
1081
  " return string.sub(rule_action_key, 1, last_name), frames\n"
@@ -1653,23 +1650,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1653
1650
  }
1654
1651
  }
1655
1652
 
1656
- if (currentNode->value.c.span > 0) {
1657
- oldLua = lua;
1658
- if (asprintf(&lua,
1659
- "%sif toggle then\n"
1660
- " context[\"process_key\"] = process_key_with_span\n"
1661
- " context[\"process_key_count\"] = %d\n"
1662
- " if not process_message(message) then\n"
1663
- " return\n"
1664
- " end\n"
1665
- "end\n",
1666
- lua,
1667
- currentNode->value.c.span) == -1) {
1668
- return ERR_OUT_OF_MEMORY;
1669
- }
1670
- free(oldLua);
1671
-
1672
- } else if (currentNode->value.c.cap > 0) {
1653
+ if (currentNode->value.c.cap > 0) {
1673
1654
  oldLua = lua;
1674
1655
  if (asprintf(&lua,
1675
1656
  "%sif toggle then\n"
@@ -1720,7 +1701,6 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1720
1701
  "local actions_key = \"%s!a\"\n"
1721
1702
  "local state_key = \"%s!s\"\n"
1722
1703
  "local mid_count_hashset = \"%s!c\"\n"
1723
- "local queue_action = false\n"
1724
1704
  "local facts_message_cache = {}\n"
1725
1705
  "local events_message_cache = {}\n"
1726
1706
  "local facts_mids_cache = {}\n"
@@ -1972,50 +1952,9 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1972
1952
  " end\n"
1973
1953
  " return result\n"
1974
1954
  "end\n"
1975
- "local process_key_with_span = function(message, span)\n"
1976
- " local index = directory[key]\n"
1977
- " local queue_lock = false\n"
1978
- " if index then\n"
1979
- " local last_score = redis.call(\"get\", results_key .. \"!d\")\n"
1980
- " if not last_score then\n"
1981
- " redis.call(\"set\", results_key .. \"!d\", score)\n"
1982
- " else\n"
1983
- " local new_score = last_score + span\n"
1984
- " if score > new_score then\n"
1985
- " redis.call(\"rpush\", results_key, 0)\n"
1986
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1987
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, 0)\n"
1988
- " local span_count, span_remain = math.modf((score - new_score) / span)\n"
1989
- " last_score = new_score + span_count * span\n"
1990
- " redis.call(\"set\", results_key .. \"!d\", last_score)\n"
1991
- " queue_lock = true\n"
1992
- " end\n"
1993
- " end\n"
1994
- " local count = 0\n"
1995
- " if not message then\n"
1996
- " if assert_fact == 0 then\n"
1997
- " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1998
- " else\n"
1999
- " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
2000
- " end\n"
2001
- " else\n"
2002
- " if assert_fact == 0 then\n"
2003
- " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
2004
- " else\n"
2005
- " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
2006
- " end\n"
2007
- " end\n"
2008
- " if (count > 0) then\n"
2009
- " for i = 1, #results, 1 do\n"
2010
- " redis.call(\"rpush\", results_key, results[i])\n"
2011
- " end\n"
2012
- " end\n"
2013
- " end\n"
2014
- " return queue_lock\n"
2015
- "end\n"
2016
1955
  "local process_key_with_cap = function(message, cap)\n"
2017
1956
  " local index = directory[key]\n"
2018
- " local queue_lock = false\n"
1957
+ " local result_recorded = false\n"
2019
1958
  " if index then\n"
2020
1959
  " local count = 0\n"
2021
1960
  " if not message then\n"
@@ -2032,6 +1971,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2032
1971
  " end\n"
2033
1972
  " end\n"
2034
1973
  " if (count > 0) then\n"
1974
+ " result_recorded = true\n"
2035
1975
  " for i = #results, 1, -1 do\n"
2036
1976
  " redis.call(\"lpush\", results_key, results[i])\n"
2037
1977
  " end\n"
@@ -2041,23 +1981,25 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2041
1981
  " if new_count > 0 then\n"
2042
1982
  " for i = 1, new_count, 1 do\n"
2043
1983
  " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
2044
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, cap)\n"
1984
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$c\" .. cap)\n"
2045
1985
  " end\n"
2046
1986
  " end\n"
2047
1987
  " if new_remain > 0 then\n"
2048
1988
  " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
2049
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, new_remain)\n"
1989
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$c\" .. new_remain)\n"
2050
1990
  " end\n"
2051
- " if new_count > 0 or new_remain > 0 then\n"
2052
- " queue_lock = true\n"
1991
+ " if new_remain > 0 or new_count > 0 then\n"
1992
+ " if not redis.call(\"zscore\", actions_key, sid) then\n"
1993
+ " redis.call(\"zadd\", actions_key , score, sid)\n"
1994
+ " end\n"
2053
1995
  " end\n"
2054
1996
  " end\n"
2055
1997
  " end\n"
2056
- " return queue_lock\n"
1998
+ " return result_recorded\n"
2057
1999
  "end\n"
2058
2000
  "local process_key_with_window = function(message, window)\n"
2059
2001
  " local index = directory[key]\n"
2060
- " local queue_lock = false\n"
2002
+ " local result_recorded = false\n"
2061
2003
  " if index then\n"
2062
2004
  " local count = 0\n"
2063
2005
  " if not message then\n"
@@ -2074,6 +2016,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2074
2016
  " end\n"
2075
2017
  " end\n"
2076
2018
  " if (count > 0) then\n"
2019
+ " result_recorded = true\n"
2077
2020
  " for i = #results, 1, -1 do\n"
2078
2021
  " redis.call(\"lpush\", results_key, results[i])\n"
2079
2022
  " end\n"
@@ -2085,17 +2028,15 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2085
2028
  " if diff > 0 then\n"
2086
2029
  " for i = 0, diff - 1, 1 do\n"
2087
2030
  " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
2088
- " if window == 1 then\n"
2089
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"single\")\n"
2090
- " else\n"
2091
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, window)\n"
2092
- " end\n"
2031
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$w\" .. window)\n"
2032
+ " end\n"
2033
+ " if not redis.call(\"zscore\", actions_key, sid) then\n"
2034
+ " redis.call(\"zadd\", actions_key , score, sid)\n"
2093
2035
  " end\n"
2094
- " queue_lock = true\n"
2095
2036
  " end\n"
2096
2037
  " end\n"
2097
2038
  " end\n"
2098
- " return queue_lock\n"
2039
+ " return result_recorded\n"
2099
2040
  "end\n"
2100
2041
  "local process_message = function(message)\n"
2101
2042
  " for index = 6, 5 + keys_count, 1 do\n"
@@ -2116,20 +2057,12 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2116
2057
  " expressions_count = context[\"expressions_count\"]\n"
2117
2058
  " local process_key = context[\"process_key\"]\n"
2118
2059
  " local process_key_count = context[\"process_key_count\"]\n"
2119
- " queue_action = process_key(message, process_key_count) or queue_action\n"
2120
- " if assert_fact == 0 and events_message_cache[tostring(message[\"id\"])] == false then\n"
2121
- " break\n"
2060
+ " local result_recorded = process_key(message, process_key_count)\n"
2061
+ " if assert_fact == 0 and result_recorded then\n"
2062
+ " return false\n"
2122
2063
  " end\n"
2123
2064
  " end\n"
2124
2065
  " end\n"
2125
- " if queue_action then\n"
2126
- " if not redis.call(\"zscore\", actions_key, sid) then\n"
2127
- " redis.call(\"zadd\", actions_key , score, sid)\n"
2128
- " end\n"
2129
- " if assert_fact == 0 then\n"
2130
- " return false\n"
2131
- " end\n"
2132
- " end\n"
2133
2066
  " return true\n"
2134
2067
  "end\n"
2135
2068
  "local message = nil\n"
@@ -2265,6 +2198,11 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
2265
2198
  return result;
2266
2199
  }
2267
2200
 
2201
+ result = loadRemoveTimerCommand(tree, rulesBinding);
2202
+ if (result != RULES_OK) {
2203
+ return result;
2204
+ }
2205
+
2268
2206
  result = loadEvalMessageCommand(tree, rulesBinding);
2269
2207
  if (result != RULES_OK) {
2270
2208
  return result;
@@ -2949,28 +2887,37 @@ unsigned int peekTimers(ruleset *tree, void **bindingContext, redisReply **reply
2949
2887
  return ERR_NO_TIMERS_AVAILABLE;
2950
2888
  }
2951
2889
 
2952
- unsigned int registerTimer(void *rulesBinding, unsigned int duration, char *timer) {
2890
+ unsigned int registerTimer(void *rulesBinding, unsigned int duration, char assert, char *timer) {
2953
2891
  binding *currentBinding = (binding*)rulesBinding;
2954
2892
  redisContext *reContext = currentBinding->reContext;
2955
2893
  time_t currentTime = time(NULL);
2956
2894
 
2957
- int result = redisAppendCommand(reContext,
2895
+ int result = RULES_OK;
2896
+ if (assert) {
2897
+ result = redisAppendCommand(reContext,
2898
+ "zadd %s %ld a:%s",
2899
+ currentBinding->timersSortedset,
2900
+ currentTime + duration,
2901
+ timer);
2902
+ } else {
2903
+ result = redisAppendCommand(reContext,
2958
2904
  "zadd %s %ld p:%s",
2959
2905
  currentBinding->timersSortedset,
2960
2906
  currentTime + duration,
2961
2907
  timer);
2908
+ }
2909
+
2962
2910
  VERIFY(result, "registerTimer");
2963
2911
  return RULES_OK;
2964
2912
  }
2965
2913
 
2966
- unsigned int removeTimer(void *rulesBinding, char *timer) {
2914
+ unsigned int removeTimer(void *rulesBinding, char *timerName) {
2967
2915
  binding *currentBinding = (binding*)rulesBinding;
2968
2916
  redisContext *reContext = currentBinding->reContext;
2969
-
2970
2917
  int result = redisAppendCommand(reContext,
2971
- "zrem %s p:%s",
2972
- currentBinding->timersSortedset,
2973
- timer);
2918
+ "evalsha %s 0 %s",
2919
+ currentBinding->removeTimerHash,
2920
+ timerName);
2974
2921
  VERIFY(result, "removeTimer");
2975
2922
  return RULES_OK;
2976
2923
  }
@@ -2980,7 +2927,7 @@ unsigned int registerMessage(void *rulesBinding, unsigned int queueAction, char
2980
2927
  redisContext *reContext = currentBinding->reContext;
2981
2928
  time_t currentTime = time(NULL);
2982
2929
 
2983
- int result = REDIS_OK;
2930
+ int result = RULES_OK;
2984
2931
 
2985
2932
  switch (queueAction) {
2986
2933
  case QUEUE_ASSERT_FACT:
@@ -30,6 +30,7 @@ typedef struct binding {
30
30
  functionHash removeActionHash;
31
31
  functionHash partitionHash;
32
32
  functionHash timersHash;
33
+ functionHash removeTimerHash;
33
34
  functionHash updateActionHash;
34
35
  functionHash deleteSessionHash;
35
36
  char *sessionHashset;
@@ -132,10 +133,11 @@ unsigned int peekTimers(ruleset *tree,
132
133
 
133
134
  unsigned int registerTimer(void *rulesBinding,
134
135
  unsigned int duration,
136
+ char assert,
135
137
  char *timer);
136
138
 
137
139
  unsigned int removeTimer(void *rulesBinding,
138
- char *timer);
140
+ char *timerName);
139
141
 
140
142
  unsigned int registerMessage(void *rulesBinding,
141
143
  unsigned int queueAction,
@@ -2,6 +2,7 @@
2
2
  #include <stdio.h>
3
3
  #include <stdlib.h>
4
4
  #include <string.h>
5
+ #include <ctype.h>
5
6
  #include "rules.h"
6
7
  #include "rete.h"
7
8
  #include "regex.h"
@@ -899,6 +900,7 @@ static unsigned int ensureState(unsigned short *id,
899
900
  unsigned short stateListLength,
900
901
  state **newState) {
901
902
  CREATE_STATE(id, newState);
903
+ unsigned short dotTransitions = 0;
902
904
  for (unsigned short i = 0; i < stateListLength; ++i) {
903
905
  state *targetState = list[i];
904
906
  for (unsigned short ii = 0; ii < targetState->transitionsLength; ++ii) {
@@ -907,6 +909,10 @@ static unsigned int ensureState(unsigned short *id,
907
909
  if (result != RULES_OK) {
908
910
  return result;
909
911
  }
912
+
913
+ if (targetTransition->symbol == REGEX_DOT) {
914
+ ++dotTransitions;
915
+ }
910
916
  }
911
917
 
912
918
  if (targetState->isAccept) {
@@ -921,6 +927,19 @@ static unsigned int ensureState(unsigned short *id,
921
927
  return ERR_REGEX_CONFLICT;
922
928
  }
923
929
  }
930
+
931
+ // when merging two states results in two or more dot transitions
932
+ // all specific transitions are cancelled, this allows for the
933
+ // first match to succeed.
934
+ if (dotTransitions > 1) {
935
+ for (unsigned short i = 0; i < (*newState)->transitionsLength; ++i) {
936
+ transition *currentTransition = &(*newState)->transitions[i];
937
+ if (currentTransition->symbol != REGEX_DOT) {
938
+ unlinkStates(*newState, currentTransition->next, currentTransition->symbol);
939
+ }
940
+ }
941
+ }
942
+
924
943
  return RULES_OK;
925
944
  }
926
945
 
@@ -1130,7 +1149,7 @@ static unsigned int transformToDFA(state *nfa,
1130
1149
  }
1131
1150
 
1132
1151
  static unsigned int expandDot(state *nfa,
1133
- unsigned short *id) {
1152
+ unsigned short *id) {
1134
1153
 
1135
1154
  CREATE_HASHSET(state*);
1136
1155
  CREATE_QUEUE(state*);
@@ -1216,7 +1235,8 @@ static unsigned short getIndex(symbolEntry *symbolHashSet, unsigned short vocabu
1216
1235
  static unsigned int packGraph(state *start,
1217
1236
  void *stateMachine,
1218
1237
  unsigned short vocabularyLength,
1219
- unsigned short statesLength) {
1238
+ unsigned short statesLength,
1239
+ char caseInsensitive) {
1220
1240
  CREATE_QUEUE(state*);
1221
1241
  unsigned short visited[MAX_STATES] = {0};
1222
1242
  symbolEntry *symbolHashSet = (symbolEntry *)stateMachine;
@@ -1235,9 +1255,13 @@ static unsigned int packGraph(state *start,
1235
1255
 
1236
1256
  for (int i = 0; i < currentState->transitionsLength; ++ i) {
1237
1257
  transition *currentTransition = &currentState->transitions[i];
1258
+ unsigned int currentTransitionSymbol = currentTransition->symbol;
1259
+ if (caseInsensitive) {
1260
+ currentTransitionSymbol = tolower(currentTransitionSymbol);
1261
+ }
1238
1262
 
1239
- if (!getIndex(symbolHashSet, vocabularyLength, currentTransition->symbol)) {
1240
- setIndex(symbolHashSet, vocabularyLength, currentTransition->symbol, vocabularyNumber);
1263
+ if (!getIndex(symbolHashSet, vocabularyLength, currentTransitionSymbol)) {
1264
+ setIndex(symbolHashSet, vocabularyLength, currentTransitionSymbol, vocabularyNumber);
1241
1265
  ++vocabularyNumber;
1242
1266
  }
1243
1267
 
@@ -1247,7 +1271,7 @@ static unsigned int packGraph(state *start,
1247
1271
  ENQUEUE(currentTransition->next);
1248
1272
  }
1249
1273
 
1250
- unsigned short targetSymbolNumber = getIndex(symbolHashSet, vocabularyLength, currentTransition->symbol);
1274
+ unsigned short targetSymbolNumber = getIndex(symbolHashSet, vocabularyLength, currentTransitionSymbol);
1251
1275
  stateTable[statesLength * (targetSymbolNumber - 1) + (targetStateNumber - 1)] = visited[currentTransition->next->id];
1252
1276
  }
1253
1277
 
@@ -1265,6 +1289,7 @@ unsigned int validateRegex(char *first,
1265
1289
  unsigned int compileRegex(void *tree,
1266
1290
  char *first,
1267
1291
  char *last,
1292
+ char caseInsensitive,
1268
1293
  unsigned short *vocabularyLength,
1269
1294
  unsigned short *statesLength,
1270
1295
  unsigned int *regexStateMachineOffset) {
@@ -1288,11 +1313,21 @@ unsigned int compileRegex(void *tree,
1288
1313
  return result;
1289
1314
  }
1290
1315
 
1316
+ #ifdef _PRINT
1317
+ printf("*** DFA 1 ***\n");
1318
+ printGraph(start);
1319
+ #endif
1320
+
1291
1321
  result = expandDot(start, &id);
1292
1322
  if (result != RULES_OK) {
1293
1323
  return result;
1294
1324
  }
1295
1325
 
1326
+ #ifdef _PRINT
1327
+ printf("*** DOT 1 ***\n");
1328
+ printGraph(start);
1329
+ #endif
1330
+
1296
1331
  result = transformToDFA(start, &id);
1297
1332
  if (result != RULES_OK) {
1298
1333
  return result;
@@ -1321,12 +1356,14 @@ unsigned int compileRegex(void *tree,
1321
1356
  return packGraph(start,
1322
1357
  newStateMachine,
1323
1358
  *vocabularyLength,
1324
- *statesLength);
1359
+ *statesLength,
1360
+ caseInsensitive);
1325
1361
  }
1326
1362
 
1327
1363
  unsigned char evaluateRegex(void *tree,
1328
1364
  char *first,
1329
1365
  unsigned short length,
1366
+ char caseInsensitive,
1330
1367
  unsigned short vocabularyLength,
1331
1368
  unsigned short statesLength,
1332
1369
  unsigned int regexStateMachineOffset) {
@@ -1340,6 +1377,10 @@ unsigned char evaluateRegex(void *tree,
1340
1377
  if (utf8ToUnicode(&first, last, &unicodeSymbol) != REGEX_PARSE_OK) {
1341
1378
  return 0;
1342
1379
  } else {
1380
+ if (caseInsensitive) {
1381
+ unicodeSymbol = tolower(unicodeSymbol);
1382
+ }
1383
+
1343
1384
  unsigned short currentSymbol = getIndex(symbolHashSet, vocabularyLength, unicodeSymbol);
1344
1385
  if (!currentSymbol) {
1345
1386
  currentSymbol = getIndex(symbolHashSet, vocabularyLength, REGEX_DOT);
@@ -8,13 +8,15 @@ unsigned int validateRegex(char *first,
8
8
  unsigned int compileRegex(void *tree,
9
9
  char *first,
10
10
  char *last,
11
+ char caseInsensitive,
11
12
  unsigned short *vocabularyLength,
12
13
  unsigned short *statesLength,
13
14
  unsigned int *regexStateMachineOffset);
14
15
 
15
16
  unsigned char evaluateRegex(void *tree,
16
17
  char *first,
17
- unsigned short length,
18
+ unsigned short length,
19
+ char caseInsensitive,
18
20
  unsigned short vocabularyLength,
19
21
  unsigned short statesLength,
20
22
  unsigned int regexStateMachineOffset);
@@ -22,6 +22,7 @@
22
22
  #define HASH_EQ 193419647 // $eq
23
23
  #define HASH_NEQ 2087890573 // $neq
24
24
  #define HASH_MT 193419914 // $mt
25
+ #define HASH_IMT 2087885395 // $imt
25
26
  #define HASH_EX 193419654 // $ex
26
27
  #define HASH_NEX 2087890580 // $nex
27
28
  #define HASH_OR 193419978 // $or
@@ -339,6 +340,7 @@ static unsigned int copyValue(ruleset *tree,
339
340
  right->value.b = leftb;
340
341
  break;
341
342
  case JSON_REGEX:
343
+ case JSON_IREGEX:
342
344
  leftLength = last - first;
343
345
  result = storeString(tree, first, &right->value.regex.stringOffset, leftLength);
344
346
  if (result != RULES_OK) {
@@ -348,6 +350,7 @@ static unsigned int copyValue(ruleset *tree,
348
350
  result = compileRegex(tree,
349
351
  first,
350
352
  last,
353
+ (type == JSON_REGEX) ? 0 : 1,
351
354
  &right->value.regex.vocabularyLength,
352
355
  &right->value.regex.statesLength,
353
356
  &right->value.regex.stateMachineOffset);
@@ -385,7 +388,7 @@ static unsigned char compareValue(ruleset *tree,
385
388
  case JSON_STRING:
386
389
  {
387
390
  char *rightString;
388
- if (right->type == JSON_REGEX) {
391
+ if (right->type == JSON_REGEX || right->type == JSON_IREGEX) {
389
392
  rightString = &tree->stringPool[right->value.regex.stringOffset];
390
393
  } else {
391
394
  rightString = &tree->stringPool[right->value.stringOffset];
@@ -590,6 +593,9 @@ static unsigned int validateExpression(char *rule) {
590
593
  case HASH_MT:
591
594
  operator = OP_MT;
592
595
  break;
596
+ case HASH_IMT:
597
+ operator = OP_IMT;
598
+ break;
593
599
  case HASH_LT:
594
600
  operator = OP_LT;
595
601
  break;
@@ -640,7 +646,7 @@ static unsigned int validateExpression(char *rule) {
640
646
  return result;
641
647
  }
642
648
 
643
- if (operator == OP_MT) {
649
+ if (operator == OP_MT || operator == OP_IMT) {
644
650
  if (type != JSON_STRING) {
645
651
  return ERR_UNEXPECTED_TYPE;
646
652
  }
@@ -1069,6 +1075,10 @@ static unsigned int findAlpha(ruleset *tree,
1069
1075
  type = JSON_REGEX;
1070
1076
  }
1071
1077
 
1078
+ if (operator == OP_IMT) {
1079
+ type = JSON_IREGEX;
1080
+ }
1081
+
1072
1082
  result = copyValue(tree, &newAlpha->value.a.right, first, last, idiomOffset, &ref, type);
1073
1083
  if (result != RULES_OK) {
1074
1084
  return result;
@@ -1155,6 +1165,9 @@ static unsigned int createAlpha(ruleset *tree,
1155
1165
  case HASH_MT:
1156
1166
  operator = OP_MT;
1157
1167
  break;
1168
+ case HASH_IMT:
1169
+ operator = OP_IMT;
1170
+ break;
1158
1171
  case HASH_LT:
1159
1172
  operator = OP_LT;
1160
1173
  break;
@@ -21,6 +21,7 @@
21
21
  #define OP_TYPE 0x12
22
22
  #define OP_NOT 0x13
23
23
  #define OP_MT 0x14
24
+ #define OP_IMT 0x15
24
25
 
25
26
  #define NODE_ALPHA 0
26
27
  #define NODE_BETA_CONNECTOR 1
@@ -164,11 +164,12 @@ unsigned int abandonAction(void *handle,
164
164
  unsigned int startTimer(void *handle,
165
165
  char *sid,
166
166
  unsigned int duration,
167
+ char manualReset,
167
168
  char *timer);
168
169
 
169
170
  unsigned int cancelTimer(void *handle,
170
171
  char *sid,
171
- char *timer);
172
+ char *timerName);
172
173
 
173
174
  unsigned int queueMessage(void *handle,
174
175
  unsigned int queueAction,
@@ -544,13 +544,14 @@ static VALUE rbAbandonAction(VALUE self, VALUE handle, VALUE actionHandle) {
544
544
  return Qnil;
545
545
  }
546
546
 
547
- static VALUE rbStartTimer(VALUE self, VALUE handle, VALUE sid, VALUE duration, VALUE timer) {
547
+ static VALUE rbStartTimer(VALUE self, VALUE handle, VALUE sid, VALUE duration, VALUE manualReset, VALUE timer) {
548
548
  Check_Type(handle, T_FIXNUM);
549
549
  Check_Type(sid, T_STRING);
550
550
  Check_Type(duration, T_FIXNUM);
551
+ Check_Type(manualReset, T_FIXNUM);
551
552
  Check_Type(timer, T_STRING);
552
553
 
553
- unsigned int result = startTimer((void *)FIX2LONG(handle), RSTRING_PTR(sid), FIX2UINT(duration), RSTRING_PTR(timer));
554
+ unsigned int result = startTimer((void *)FIX2LONG(handle), RSTRING_PTR(sid), FIX2UINT(duration), FIX2SHORT(manualReset), RSTRING_PTR(timer));
554
555
  if (result != RULES_OK) {
555
556
  if (result == ERR_OUT_OF_MEMORY) {
556
557
  rb_raise(rb_eNoMemError, "Out of memory");
@@ -562,12 +563,12 @@ static VALUE rbStartTimer(VALUE self, VALUE handle, VALUE sid, VALUE duration, V
562
563
  return Qnil;
563
564
  }
564
565
 
565
- static VALUE rbCancelTimer(VALUE self, VALUE handle, VALUE sid, VALUE timer) {
566
+ static VALUE rbCancelTimer(VALUE self, VALUE handle, VALUE sid, VALUE timerName) {
566
567
  Check_Type(handle, T_FIXNUM);
567
568
  Check_Type(sid, T_STRING);
568
- Check_Type(timer, T_STRING);
569
+ Check_Type(timerName, T_STRING);
569
570
 
570
- unsigned int result = cancelTimer((void *)FIX2LONG(handle), RSTRING_PTR(sid), RSTRING_PTR(timer));
571
+ unsigned int result = cancelTimer((void *)FIX2LONG(handle), RSTRING_PTR(sid), RSTRING_PTR(timerName));
571
572
  if (result != RULES_OK) {
572
573
  if (result == ERR_OUT_OF_MEMORY) {
573
574
  rb_raise(rb_eNoMemError, "Out of memory");
@@ -679,7 +680,7 @@ void Init_rules() {
679
680
  rb_define_singleton_method(rulesModule, "complete_action", rbCompleteAction, 3);
680
681
  rb_define_singleton_method(rulesModule, "complete_and_start_action", rbCompleteAndStartAction, 3);
681
682
  rb_define_singleton_method(rulesModule, "abandon_action", rbAbandonAction, 2);
682
- rb_define_singleton_method(rulesModule, "start_timer", rbStartTimer, 4);
683
+ rb_define_singleton_method(rulesModule, "start_timer", rbStartTimer, 5);
683
684
  rb_define_singleton_method(rulesModule, "cancel_timer", rbCancelTimer, 3);
684
685
  rb_define_singleton_method(rulesModule, "assert_timers", rbAssertTimers, 1);
685
686
  rb_define_singleton_method(rulesModule, "get_state", rbGetState, 2);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: durable_rules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.27
4
+ version: 0.34.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesus Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-30 00:00:00.000000000 Z
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake