flor 1.6.2 → 1.6.4
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 +4 -4
- data/CHANGELOG.md +15 -1
- data/CREDITS.md +1 -0
- data/LICENSE.txt +1 -1
- data/README.md +10 -3
- data/flor.gemspec +1 -1
- data/lib/flor/colours.rb +52 -52
- data/lib/flor/conf.rb +3 -3
- data/lib/flor/core/executor.rb +1 -1
- data/lib/flor/core/procedure.rb +16 -6
- data/lib/flor/core/texecutor.rb +4 -4
- data/lib/flor/core.rb +65 -52
- data/lib/flor/parser.rb +27 -24
- data/lib/flor/pcore/andor.rb +1 -1
- data/lib/flor/pcore/apply.rb +1 -1
- data/lib/flor/pcore/break.rb +3 -3
- data/lib/flor/pcore/case.rb +1 -1
- data/lib/flor/pcore/cursor.rb +11 -1
- data/lib/flor/pcore/define.rb +1 -1
- data/lib/flor/pcore/del.rb +81 -0
- data/lib/flor/pcore/fail.rb +1 -1
- data/lib/flor/pcore/if.rb +21 -0
- data/lib/flor/pcore/iterator.rb +2 -3
- data/lib/flor/pcore/match.rb +1 -1
- data/lib/flor/pcore/reverse.rb +1 -1
- data/lib/flor/pcore/set.rb +1 -1
- data/lib/flor/pcore/until.rb +1 -1
- data/lib/flor/punit/c_iterator.rb +1 -0
- data/lib/flor/punit/signal.rb +1 -1
- data/lib/flor/punit/trap.rb +1 -1
- data/lib/flor/to_string.rb +39 -36
- data/lib/flor/tools/env.rb +51 -48
- data/lib/flor/tools/shell.rb +12 -9
- data/lib/flor/unit/journal.rb +8 -0
- data/lib/flor/unit/scheduler.rb +27 -20
- data/lib/flor/unit/storage.rb +2 -1
- data/lib/flor.rb +1 -1
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 726f12169dd650e862f4fdcf7f08da2e08f9a06ccf9f9125b2ad0340b4003b1f
|
4
|
+
data.tar.gz: 4864b67e47ee79e8a9b220e2465d23343e554102fd8a8fbdac6dad16eef9327c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82a526fd4cd0c6185e3778e4b1421c6f120fa3b0a3c3591a54fb7ddb2ddae7943302409a5b1fe1bec118882ebaf125cdd6b35895f442d58b32068c80e17497b4
|
7
|
+
data.tar.gz: 80ab4a60ca328565ce463459ee610face1f9d513da541392c1d6c7b8bf0906c9271120dd1dbd94ea66589eda8c3112233f817d1ef6a38eb931bece7eda1cac7a
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,21 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
-
## flor 1.6.
|
5
|
+
## flor 1.6.4 released 2025-09-18
|
6
|
+
|
7
|
+
* Introduce `del` and `delf` to delete vars and fields
|
8
|
+
* Fix cursor/move vs symbol target
|
9
|
+
|
10
|
+
|
11
|
+
## flor 1.6.3 released 2025-05-29
|
12
|
+
|
13
|
+
* Stop Scheduler#notify swallowing errors, gh-43
|
14
|
+
* Rework max_execution_count conf and use, gh-41
|
15
|
+
* Introduce Flor.pp(o, opts={}) and Flor.pp_to_s
|
16
|
+
* Set skip_transaction: true when reimporting ptrs
|
17
|
+
|
18
|
+
|
19
|
+
## flor 1.6.2 released 2023-12-03
|
6
20
|
|
7
21
|
* Prevent djan failing on negative indent for hash keys
|
8
22
|
|
data/CREDITS.md
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
Copyright (c) 2015-
|
2
|
+
Copyright (c) 2015-2025, John Mettraux, jmettraux+flor@gmail.com
|
3
3
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -6,8 +6,10 @@
|
|
6
6
|
|
7
7
|
Flor is a "Ruby workflow engine", if that makes any sense.
|
8
8
|
|
9
|
+
<!--
|
9
10
|
* [floraison mailing list](https://groups.google.com/forum/#!forum/floraison)
|
10
11
|
* [twitter.com/@flor_workflow](https://twitter.com/flor_workflow)
|
12
|
+
-->
|
11
13
|
|
12
14
|
|
13
15
|
## use
|
@@ -36,7 +38,7 @@ Using flor in your Ruby project requires you to clearly separate business proces
|
|
36
38
|
|
37
39
|
## quickstart
|
38
40
|
|
39
|
-
This quickstart sets up a flor unit tied to a SQLite database, resets the
|
41
|
+
This quickstart sets up a flor unit tied to a SQLite database, resets the database, binds two taskers and then launches a flow execution involving the two taskers. Finally, it prints out the resulting workitem as the execution has just terminated.
|
40
42
|
|
41
43
|
```ruby
|
42
44
|
require 'flor/unit'
|
@@ -94,7 +96,7 @@ p r['payload']['log']
|
|
94
96
|
|
95
97
|
This quickstart is at [doc/quickstart0/](doc/quickstart0/), it's a minimal, one-file Ruby quickstart.
|
96
98
|
|
97
|
-
There is also [doc/quickstart1/](doc/quickstart1/), a more complex example, that shows a flor setup, where taskers and flows are
|
99
|
+
There is also [doc/quickstart1/](doc/quickstart1/), a more complex example, that shows a flor setup, where taskers and flows are laid out in a flor directory tree.
|
98
100
|
|
99
101
|
|
100
102
|
## documentation
|
@@ -114,6 +116,8 @@ See [doc/](doc/).
|
|
114
116
|
* [floraison/flack](https://github.com/floraison/flack) - a flor wrapping [Rack](https://github.com/rack/rack) app
|
115
117
|
* [floraison/fugit](https://github.com/floraison/fugit) - a time library for flor and [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler)
|
116
118
|
* [floraison/raabro](https://github.com/floraison/raabro) - the PEG library flor uses for its parsing needs
|
119
|
+
* [kiebor81/flor-language-service](https://github.com/kiebor81/flor-language-service) - a Visual Studio Code language service for the Flor language
|
120
|
+
* [flor.vim](https://github.com/floraison/flor/blob/master/misc/flor.vim) - a Vim syntax file for flor
|
117
121
|
|
118
122
|
|
119
123
|
## blog posts and presentations
|
@@ -138,10 +142,13 @@ There are various other Ruby and Ruby on Rails projects about workflows and busi
|
|
138
142
|
* [Petri Flow](https://github.com/hooopo/petri_flow) - "Petri Net Workflow Engine for Ruby" (Rails)
|
139
143
|
* [Pallets](https://github.com/linkyndy/pallets) - "Simple and reliable workflow engine, written in Ruby"
|
140
144
|
* [Gush](https://github.com/chaps-io/gush) - "Fast and distributed workflow runner using ActiveJob and Redis"
|
145
|
+
* [Rukawa](https://github.com/joker1007/rukawa) - Hyper simple workflow engine powered by concurrent-ruby
|
146
|
+
* [ChronoForge](https://github.com/radioactive-labs/chrono_forge) - durable workflow engine for Ruby on Rails that provides reliable state management, error recovery, and workflow orchestration through ActiveJob
|
147
|
+
* [StepperMotor](https://github.com/stepper-motor/stepper_motor) - Effortless step workflows for Rails
|
141
148
|
|
142
149
|
There is a [workflow engine](https://ruby.libhunt.com/categories/5786-workflow-engine) category on [Awesome Ruby](https://ruby.libhunt.com/).
|
143
150
|
|
144
|
-
If you want your engine/library to be added in this list, don't hesitate to ask me on [
|
151
|
+
If you want your engine/library to be added in this list, don't hesitate to ask me on via an [issue](https://github.com/floraison/flor/issues) or a pull request.
|
145
152
|
|
146
153
|
It's not limited to Ruby, but there is a wider list at [meirwah/awesome-workflow-engines](https://github.com/meirwah/awesome-workflow-engines).
|
147
154
|
|
data/flor.gemspec
CHANGED
@@ -40,7 +40,7 @@ A Ruby workflow engine (ruote next generation)
|
|
40
40
|
#s.add_runtime_dependency 'rufus-lru', '~> 1.1'
|
41
41
|
s.add_runtime_dependency 'munemo', '~> 1.0' # >= 1.0 and < 2
|
42
42
|
s.add_runtime_dependency 'raabro', '~> 1.1' # >= 1.1 and < 2
|
43
|
-
s.add_runtime_dependency 'fugit', '~> 1.
|
43
|
+
s.add_runtime_dependency 'fugit', '~> 1.10', '>= 1.11.1' # >= 1.2 and < 2
|
44
44
|
s.add_runtime_dependency 'dense', '~> 1.1' # >= 1.1 and < 2
|
45
45
|
|
46
46
|
s.add_runtime_dependency 'sequel', '~> 5.0' # >= 5.0 and < 6
|
data/lib/flor/colours.rb
CHANGED
@@ -53,78 +53,78 @@ module Flor
|
|
53
53
|
@colours = Colours.new
|
54
54
|
@no_colours = NoColours.new
|
55
55
|
|
56
|
-
|
56
|
+
class << self
|
57
57
|
|
58
|
-
|
59
|
-
end
|
58
|
+
def no_colours
|
60
59
|
|
61
|
-
|
60
|
+
@no_colours
|
61
|
+
end
|
62
62
|
|
63
|
-
|
64
|
-
# case opts
|
65
|
-
# when Hash then opts
|
66
|
-
# when Colours, NoColours then { color: opts }
|
67
|
-
# else { out: opts }
|
68
|
-
# end
|
63
|
+
def colours(opts={})
|
69
64
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
#opts =
|
66
|
+
# case opts
|
67
|
+
# when Hash then opts
|
68
|
+
# when Colours, NoColours then { color: opts }
|
69
|
+
# else { out: opts }
|
70
|
+
# end
|
74
71
|
|
75
|
-
|
76
|
-
|
72
|
+
c = nil;
|
73
|
+
[ :color, :colour, :colors, :colours ].each do |k|
|
74
|
+
if opts.has_key?(k); c = opts[k]; break; end
|
75
|
+
end
|
77
76
|
|
78
|
-
|
77
|
+
return @colours if c == true
|
78
|
+
return @no_colours if c == false
|
79
79
|
|
80
|
-
|
81
|
-
(o.respond_to?(:log_colours?) ? o.log_colours? : o.tty?) ||
|
82
|
-
($0[-6..-1] == '/rspec' &&
|
83
|
-
(ARGV.include?('--tty') || ARGV.include?('--color'))))
|
80
|
+
o = opts[:out] || $stdout
|
84
81
|
|
85
|
-
|
86
|
-
|
82
|
+
return @colours if (
|
83
|
+
(o.respond_to?(:log_colours?) ? o.log_colours? : o.tty?) ||
|
84
|
+
($0[-6..-1] == '/rspec' &&
|
85
|
+
(ARGV.include?('--tty') || ARGV.include?('--color'))))
|
87
86
|
|
88
|
-
|
87
|
+
@no_colours
|
88
|
+
end
|
89
89
|
|
90
|
-
s
|
91
|
-
end
|
90
|
+
def decolour(s)
|
92
91
|
|
93
|
-
|
92
|
+
s.gsub(/\x1b\[\d+(;\d+)?m/, '')
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
end
|
95
|
+
def no_colour_length(s)
|
97
96
|
|
98
|
-
|
97
|
+
decolour(s).length
|
98
|
+
end
|
99
99
|
|
100
|
-
|
101
|
-
r = StringIO.new
|
102
|
-
l = 0
|
100
|
+
def truncate_string(s, maxlen, post='...')
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
ncl = no_colour_length(s)
|
103
|
+
r = StringIO.new
|
104
|
+
l = 0
|
105
|
+
|
106
|
+
s.scan(/(\x1b\[\d+(?:;\d+)?m|[^\x1b]+)/) do |ss, _|
|
107
|
+
if ss[0, 1] == ""
|
108
|
+
r << ss
|
109
|
+
else
|
108
110
|
#p({ r: r.string, l: l, ssl: ss.length, maxlen: maxlen, reml: maxlen - l })
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
ss = ss[0, maxlen - l]
|
112
|
+
r << ss
|
113
|
+
l += ss.length
|
114
|
+
break if l >= maxlen
|
115
|
+
end
|
113
116
|
end
|
114
|
-
end
|
115
117
|
|
116
|
-
|
117
|
-
|
118
|
-
if post.is_a?(String)
|
119
|
-
r << post
|
120
|
-
elsif post.is_a?(Proc)
|
121
|
-
r << post.call(ncl, maxlen, s)
|
122
|
-
end
|
118
|
+
return r.string if l < maxlen
|
123
119
|
|
124
|
-
|
125
|
-
|
120
|
+
if post.is_a?(String)
|
121
|
+
r << post
|
122
|
+
elsif post.is_a?(Proc)
|
123
|
+
r << post.call(ncl, maxlen, s)
|
124
|
+
end
|
126
125
|
|
127
|
-
|
126
|
+
r.string
|
127
|
+
end
|
128
128
|
|
129
129
|
alias decolor decolour
|
130
130
|
|
data/lib/flor/conf.rb
CHANGED
@@ -30,8 +30,8 @@ module Flor
|
|
30
30
|
# reload/resync with db after how much time? (defaults to 60 (seconds))
|
31
31
|
# minimizes communication with db in idle periods
|
32
32
|
#
|
33
|
-
# * :sch_max_executors
|
34
|
-
# How many executor
|
33
|
+
# * :sch_max_executors or :sch_max_executor_count
|
34
|
+
# How many executor threads at most? (defaults to 7, 1 is OK in certain
|
35
35
|
# environments)
|
36
36
|
#
|
37
37
|
# * :exe_max_messages
|
@@ -101,7 +101,7 @@ module Flor
|
|
101
101
|
c.merge!(interpret_env)
|
102
102
|
end
|
103
103
|
|
104
|
-
c.merge!(over_conf)
|
104
|
+
c.merge!(Flor.to_string_keyed_hash(over_conf))
|
105
105
|
end
|
106
106
|
|
107
107
|
def get_class(conf, key)
|
data/lib/flor/core/executor.rb
CHANGED
@@ -156,7 +156,7 @@ module Flor
|
|
156
156
|
end
|
157
157
|
#
|
158
158
|
# vars: variables
|
159
|
-
# vdomain: variable domain (used in
|
159
|
+
# vdomain: variable domain (used in conjunction with the loader)
|
160
160
|
# cnid: closure nid
|
161
161
|
# dbg: used to debug messages (useful @node['dbg'] when 'receive')
|
162
162
|
|
data/lib/flor/core/procedure.rb
CHANGED
@@ -737,23 +737,28 @@ class Flor::Procedure < Flor::Node
|
|
737
737
|
node = lookup_var_node(@node, mode, path)
|
738
738
|
node = lookup_var_node(@node, 'l', path) if node.nil? && mode == ''
|
739
739
|
|
740
|
-
|
740
|
+
if node
|
741
|
+
return Dense.unset(node['vars'], path) if v == :UNSET
|
742
|
+
return Dense.set(node['vars'], path, v)
|
743
|
+
end
|
741
744
|
|
742
745
|
rescue IndexError
|
743
746
|
end
|
744
747
|
|
745
748
|
fail IndexError.new(
|
746
|
-
"couldn't
|
749
|
+
"couldn't #{v == :UNSET ? 'un' : ''}set var " +
|
750
|
+
"#{Flor.path_to_s([ "#{mode}v" ] + path)}")
|
747
751
|
end
|
748
752
|
|
749
753
|
def set_field(path, v)
|
750
754
|
|
755
|
+
return Dense.unset(payload.copy, path) if v == :UNSET
|
751
756
|
Dense.set(payload.copy, path, v)
|
752
757
|
|
753
758
|
rescue IndexError
|
754
759
|
|
755
760
|
fail IndexError.new(
|
756
|
-
"couldn't set field #{Flor.path_to_s(path)}")
|
761
|
+
"couldn't #{v == :UNSET ? 'un' : ''}set field #{Flor.path_to_s(path)}")
|
757
762
|
end
|
758
763
|
|
759
764
|
def set_value(path, value)
|
@@ -775,6 +780,11 @@ class Flor::Procedure < Flor::Node
|
|
775
780
|
end
|
776
781
|
end
|
777
782
|
|
783
|
+
def unset_value(path)
|
784
|
+
|
785
|
+
set_value(path, :UNSET)
|
786
|
+
end
|
787
|
+
|
778
788
|
def splat_value(paths, value)
|
779
789
|
|
780
790
|
val = value.dup
|
@@ -872,7 +882,7 @@ class Flor::Procedure < Flor::Node
|
|
872
882
|
end
|
873
883
|
|
874
884
|
# Called by the executor, in turns call cancel and cancel_when_ methods
|
875
|
-
# which may be
|
885
|
+
# which may be overridden.
|
876
886
|
#
|
877
887
|
def do_cancel
|
878
888
|
|
@@ -908,7 +918,7 @@ class Flor::Procedure < Flor::Node
|
|
908
918
|
end
|
909
919
|
|
910
920
|
# Called by the executor, in turns call kill and kill_when_ methods
|
911
|
-
# which may be
|
921
|
+
# which may be overridden.
|
912
922
|
#
|
913
923
|
def do_kill
|
914
924
|
|
@@ -941,7 +951,7 @@ class Flor::Procedure < Flor::Node
|
|
941
951
|
[] # no effect
|
942
952
|
end
|
943
953
|
|
944
|
-
# The core cancel work, is
|
954
|
+
# The core cancel work, is overridden by some procedure implementations.
|
945
955
|
#
|
946
956
|
def cancel
|
947
957
|
|
data/lib/flor/core/texecutor.rb
CHANGED
@@ -20,12 +20,12 @@ module Flor
|
|
20
20
|
@archive = nil
|
21
21
|
end
|
22
22
|
|
23
|
-
def notify(executor,
|
23
|
+
def notify(executor, message)
|
24
24
|
|
25
|
-
return [] if
|
25
|
+
return [] if message['consumed']
|
26
26
|
|
27
|
-
@logger.notify(executor,
|
28
|
-
@journal <<
|
27
|
+
@logger.notify(executor, message)
|
28
|
+
@journal << message
|
29
29
|
|
30
30
|
[]
|
31
31
|
end
|
data/lib/flor/core.rb
CHANGED
@@ -2,80 +2,93 @@
|
|
2
2
|
|
3
3
|
module Flor
|
4
4
|
|
5
|
-
|
5
|
+
class << self
|
6
6
|
|
7
|
-
|
8
|
-
@exid_mutex ||= Mutex.new
|
7
|
+
def generate_exid(domain, unit)
|
9
8
|
|
10
|
-
|
9
|
+
@exid_counter ||= 0
|
10
|
+
@exid_mutex ||= Mutex.new
|
11
11
|
|
12
|
-
|
13
|
-
@exid_mutex.synchronize do
|
12
|
+
t = Time.now.utc
|
14
13
|
|
15
|
-
|
14
|
+
sus =
|
15
|
+
@exid_mutex.synchronize do
|
16
16
|
|
17
|
-
|
18
|
-
@exid_counter = 0 if @exid_counter > 99
|
17
|
+
sus = t.sec * 100000000 + t.usec * 100 + @exid_counter
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
@exid_counter = @exid_counter + 1
|
20
|
+
@exid_counter = 0 if @exid_counter > 99
|
22
21
|
|
23
|
-
|
22
|
+
Munemo.to_s(sus)
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
end
|
25
|
+
t = t.strftime('%Y%m%d.%H%M')
|
27
26
|
|
28
|
-
|
27
|
+
"#{domain}-#{unit}-#{t}.#{sus}"
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
tree.is_a?(String) ?
|
32
|
-
Flor.parse(tree, opts[:fname] || opts[:path], opts) :
|
33
|
-
tree
|
30
|
+
def make_launch_msg(exid, tree, opts)
|
34
31
|
|
35
|
-
|
32
|
+
t =
|
33
|
+
tree.is_a?(String) ?
|
34
|
+
Flor.parse(tree, opts[:fname] || opts[:path], opts) :
|
35
|
+
tree
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
#
|
37
|
+
unless t
|
38
|
+
|
39
|
+
#h = opts.merge(prune: false, rewrite: false, debug: 0)
|
40
|
+
#Raabro.pp(Flor.parse(tree, h[:fname], h))
|
41
|
+
# TODO re-parse and indicate what went wrong...
|
42
|
+
|
43
|
+
fail ArgumentError.new(
|
44
|
+
"flow parsing failed: " + tree.inspect[0, 35] + '...')
|
45
|
+
end
|
46
|
+
|
47
|
+
pl = opts[:payload] || opts[:fields] || {}
|
48
|
+
vs = opts[:variables] || opts[:vars] || {}
|
40
49
|
|
41
50
|
fail ArgumentError.new(
|
42
|
-
"
|
43
|
-
|
51
|
+
"given launch payload should be a Hash, but it's a #{pl.class}"
|
52
|
+
) unless pl.is_a?(Hash)
|
53
|
+
fail ArgumentError.new(
|
54
|
+
"given launch variables should come in a Hash, but it's a #{vs.class}"
|
55
|
+
) unless vs.is_a?(Hash)
|
44
56
|
|
45
|
-
|
46
|
-
|
57
|
+
msg = {
|
58
|
+
'point' => 'execute',
|
59
|
+
'exid' => exid,
|
60
|
+
'nid' => '0',
|
61
|
+
'tree' => t,
|
62
|
+
'payload' => pl,
|
63
|
+
'vars' => vs }
|
47
64
|
|
48
|
-
|
49
|
-
|
50
|
-
) unless pl.is_a?(Hash)
|
51
|
-
fail ArgumentError.new(
|
52
|
-
"given launch variables should come in a Hash, but it's a #{vs.class}"
|
53
|
-
) unless vs.is_a?(Hash)
|
65
|
+
msg['vdomain'] = opts[:vdomain] \
|
66
|
+
if opts.has_key?(:vdomain)
|
54
67
|
|
55
|
-
|
56
|
-
|
57
|
-
'exid' => exid,
|
58
|
-
'nid' => '0',
|
59
|
-
'tree' => t,
|
60
|
-
'payload' => pl,
|
61
|
-
'vars' => vs }
|
68
|
+
msg
|
69
|
+
end
|
62
70
|
|
63
|
-
|
64
|
-
if opts.has_key?(:vdomain)
|
71
|
+
def load_procedures(dir)
|
65
72
|
|
66
|
-
|
67
|
-
|
73
|
+
dirpath =
|
74
|
+
if dir.match(/\A[.\/]/)
|
75
|
+
File.join(dir, '*.rb')
|
76
|
+
else
|
77
|
+
File.join(File.dirname(__FILE__), dir, '*.rb')
|
78
|
+
end
|
68
79
|
|
69
|
-
|
80
|
+
Dir[dirpath].sort.each { |path| require(path) }
|
81
|
+
end
|
70
82
|
|
71
|
-
|
72
|
-
if dir.match(/\A[.\/]/)
|
73
|
-
File.join(dir, '*.rb')
|
74
|
-
else
|
75
|
-
File.join(File.dirname(__FILE__), dir, '*.rb')
|
76
|
-
end
|
83
|
+
def pp(o, opts={})
|
77
84
|
|
78
|
-
|
85
|
+
puts Flor.to_djan(o, { indent: 2, width: true }.merge(opts))
|
86
|
+
end
|
87
|
+
|
88
|
+
def pp_to_s(o, opts={})
|
89
|
+
|
90
|
+
Flor.to_djan(o, { indent: 2, width: true }.merge(opts))
|
91
|
+
end
|
79
92
|
end
|
80
93
|
end
|
81
94
|
|
data/lib/flor/parser.rb
CHANGED
@@ -697,42 +697,45 @@ fail "don't know how to invert #{operation.inspect}" # FIXME
|
|
697
697
|
alias rewrite_panode rewrite_flor
|
698
698
|
end # module Parser
|
699
699
|
|
700
|
-
|
700
|
+
class << self
|
701
701
|
|
702
|
-
|
702
|
+
def unescape_u(cs)
|
703
703
|
|
704
|
-
|
705
|
-
|
704
|
+
s = ''; 4.times { s << cs.next }
|
705
|
+
|
706
|
+
[ s.to_i(16) ].pack('U*')
|
707
|
+
end
|
706
708
|
|
707
|
-
|
709
|
+
def unescape(s)
|
708
710
|
|
709
|
-
|
711
|
+
sio = StringIO.new
|
710
712
|
|
711
|
-
|
713
|
+
cs = s.each_char
|
712
714
|
|
713
|
-
|
715
|
+
loop do
|
714
716
|
|
715
|
-
|
717
|
+
c = cs.next
|
716
718
|
|
717
|
-
|
719
|
+
break unless c
|
718
720
|
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
721
|
+
if c == '\\'
|
722
|
+
case cn = cs.next
|
723
|
+
when 'u' then sio.print(unescape_u(cs))
|
724
|
+
when '\\', '"', '\'' then sio.print(cn)
|
725
|
+
when 'b' then sio.print("\b")
|
726
|
+
when 'f' then sio.print("\f")
|
727
|
+
when 'n' then sio.print("\n")
|
728
|
+
when 'r' then sio.print("\r")
|
729
|
+
when 't' then sio.print("\t")
|
730
|
+
else sio.print("\\#{cn}")
|
731
|
+
end
|
732
|
+
else
|
733
|
+
sio.print(c)
|
729
734
|
end
|
730
|
-
else
|
731
|
-
sio.print(c)
|
732
735
|
end
|
733
|
-
end
|
734
736
|
|
735
|
-
|
737
|
+
sio.string
|
738
|
+
end
|
736
739
|
end
|
737
740
|
end
|
738
741
|
|
data/lib/flor/pcore/andor.rb
CHANGED
data/lib/flor/pcore/apply.rb
CHANGED
data/lib/flor/pcore/break.rb
CHANGED
@@ -7,8 +7,8 @@ class Flor::Pro::Break < Flor::Procedure
|
|
7
7
|
# ```
|
8
8
|
# until false
|
9
9
|
# # do something
|
10
|
-
# continue if f.x == 0
|
11
|
-
# break if f.x == 1
|
10
|
+
# continue _ if f.x == 0
|
11
|
+
# break _ if f.x == 1
|
12
12
|
# # do something more
|
13
13
|
# ```
|
14
14
|
#
|
@@ -50,7 +50,7 @@ class Flor::Pro::Break < Flor::Procedure
|
|
50
50
|
#
|
51
51
|
# While, until, loop and cursor.
|
52
52
|
|
53
|
-
|
53
|
+
names %w[ break continue ]
|
54
54
|
|
55
55
|
def pre_execute
|
56
56
|
|
data/lib/flor/pcore/case.rb
CHANGED
@@ -88,7 +88,7 @@ class Flor::Pro::Case < Flor::Procedure
|
|
88
88
|
#
|
89
89
|
# ### defaulting to f.ret
|
90
90
|
#
|
91
|
-
# When nothing is
|
91
|
+
# When nothing is explicitly provided for consideration by "case", the
|
92
92
|
# incoming `f.ret` is used.
|
93
93
|
#
|
94
94
|
# ```
|
data/lib/flor/pcore/cursor.rb
CHANGED
@@ -191,6 +191,7 @@ class Flor::Pro::Cursor < Flor::Procedure
|
|
191
191
|
find_string_target(to) ||
|
192
192
|
find_name_target(to) ||
|
193
193
|
find_att_target(to) ||
|
194
|
+
#find_att_value_target(to) ||
|
194
195
|
fail(Flor::FlorError.new("move target #{to.inspect} not found", self))
|
195
196
|
end
|
196
197
|
|
@@ -246,7 +247,16 @@ class Flor::Pro::Cursor < Flor::Procedure
|
|
246
247
|
c[1].find { |cc|
|
247
248
|
cc[0] == '_att' &&
|
248
249
|
cc[1].is_a?(Array) &&
|
249
|
-
cc[1][0][0, 2] == [
|
250
|
+
cc[1][0][0, 2] == [ to, [] ] } }
|
250
251
|
end
|
252
|
+
|
253
|
+
#def find_att_value_target(to)
|
254
|
+
# tree[1]
|
255
|
+
# .index { |c|
|
256
|
+
# c[1].find { |cc|
|
257
|
+
# cc[1].length == 2 &&
|
258
|
+
# cc[1][0][0] != 'to' &&
|
259
|
+
# Flor.is_string_tree?(cc[1][1], to) } }
|
260
|
+
#end
|
251
261
|
end
|
252
262
|
|