durable_rules 0.34.27 → 0.34.28

Sign up to get free protection for your applications and to get access to all the features.
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