flow-lite 1.0.0 → 1.0.1

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: e984e29ecd1e215ac23dfbc248b5b323236f21ba
4
- data.tar.gz: 8105559c7ac2c17840f5efb0e9b0c4fec179bdc1
3
+ metadata.gz: 1f61f94156b9718eb74e5a99f9e9c1128f067588
4
+ data.tar.gz: b3da7ea83777db3cbe01609ae431bd4ce043ef1d
5
5
  SHA512:
6
- metadata.gz: 7e968604c3af2d83da673be18d8db52c0534e6644c29da6925bbfc6319386d52718e02845e9a057d2be7f05c6447a4abadaadd84b909235d6bc84182f6ace123
7
- data.tar.gz: c40e200d14aebf20b9d6f67595f5e2571111589efe2f0e852d681f75056b2aa49f640aa2d950b35d7b8d01e6f9720219e035646570ec1a8a5618ac74f64df9d9
6
+ metadata.gz: 49523aa490c50d6b4602090df7c135899f234b9649c406c6f5ca22967bc976732e3a3c5d6589b6c8ebdd31049651b53d2096a038e611a20a1aa5aa5b85f1565f
7
+ data.tar.gz: 4321ffd322f70a5288f68d697b4020a8389ac45f273c4f3fd88c7d5e54f104e48e6b1d5be32ee130df158472a69a64e97d0705f2f5380a03e2b474d25132ea37
data/README.md CHANGED
@@ -10,6 +10,7 @@ flow-lite gem - (yet) another (lite) workflow engine; let's you define your work
10
10
 
11
11
 
12
12
 
13
+
13
14
  ## Usage
14
15
 
15
16
 
@@ -19,12 +20,12 @@ Define the workflow steps in a Flowfile. Example:
19
20
  ``` ruby
20
21
  step :first_step do
21
22
  puts "first_step"
22
- second_step # note: you can call other steps like methods
23
+ step :second_step # note: you can call other steps with step
23
24
  end
24
25
 
25
26
  step :second_step do
26
27
  puts "second_step"
27
- third_step
28
+ step :third_step
28
29
  end
29
30
 
30
31
  step :third_step do
@@ -39,7 +40,28 @@ Example:
39
40
  $ flow first_step
40
41
  ```
41
42
 
42
- Note: By default the `flow` command line tool reads in the `Flowfile`. Use `-f/--flowfile` option to use a different file.
43
+ Note: By default the `flow` command line tool reads in and looks for `flowfile`, `Flowfile`, `flowfile.rb`, `Flowfile.rb`
44
+ in that order.
45
+ Use the `-f/--flowfile` option to use a different file
46
+ and use the `-r/--require` to (auto-)require
47
+ some extra libraries or scripts.
48
+ By default for now the "prelude / prolog" that always
49
+ gets auto-required includes:
50
+
51
+ ``` ruby
52
+ require 'pp'
53
+ require 'time'
54
+ require 'date'
55
+ require 'json'
56
+ require 'yaml'
57
+ require 'fileutils'
58
+
59
+ require 'uri'
60
+ require 'net/http'
61
+ require 'net/https'
62
+ ```
63
+
64
+ Tip: See the [`flow-lite.rb`](https://github.com/rubycoco/git/blob/master/flow-lite/lib/flow-lite.rb) source for the definite always up-to-date list.
43
65
 
44
66
 
45
67
  That's it for now.
@@ -66,14 +88,17 @@ flowfile = Flow::Flowfile.load( <<TXT )
66
88
  end
67
89
  TXT
68
90
 
69
- flow = flowfile.flow # (auto-)builds a flow class (see Note 1)
70
- # and constructs/returns an instance
71
- flow.hello #=> "Hello, world!"
72
- flow.hola #=> "¡Hola, mundo!"
91
+ flow = flowfile.flow_class.new # (auto-)build a flow class (see Note 1)
92
+ # and construct/return a new instance
93
+ flow.step_hello #=> "Hello, world!"
94
+ flow.step_hola #=> "¡Hola, mundo!"
95
+ flow.step( :hello ) #=> "Hello, world!"
96
+ flow.step( :hola ) #=> "¡Hola, mundo!"
97
+ flow.class.step_methods #=> [:hello, :hola]
73
98
 
74
99
  # or use ruby's (regular) message/metaprogramming machinery
75
- flow.send( :hello ) #=> "Hello, world!"
76
- flow.send( :hola ) #=> "¡Hola, mundo!"
100
+ flow.send( :step_hello ) #=> "Hello, world!"
101
+ flow.send( :step_hola ) #=> "¡Hola, mundo!"
77
102
  # or try
78
103
  flow.class.instance_methods.grep( /^step_/ ) #=> [:step_hello, :step_hola]
79
104
  # ...
@@ -95,19 +120,40 @@ gets used to (auto-) build (via metaprogramming) a flow class like:
95
120
 
96
121
  ``` ruby
97
122
  class Greeter < Flow::Base
98
- def hello
123
+ def step_hello
99
124
  puts "Hello, world!"
100
125
  end
101
- alias_method :step_hello, :hello
102
126
 
103
- def hola
127
+ def step_hola
104
128
  puts "¡Hola, mundo!"
105
129
  end
106
- alias_method :step_hola, :hola
107
130
  end
108
131
  ```
109
132
 
110
133
 
134
+ Note: Behind the stage the metaprogramming "class macro"
135
+ `define_step( symbol, method )`
136
+ or `define_step( symbol ) { block }` defined in `Flow::Base`
137
+ gets used, thus,
138
+ if you want to create steps in a "hand-coded" class
139
+ use:
140
+
141
+
142
+ ``` ruby
143
+ class Greeter < Flow::Base
144
+ define_step :hello do
145
+ puts "Hello, world!"
146
+ end
147
+
148
+ define_step :hola do
149
+ puts "¡Hola, mundo!"
150
+ end
151
+ end
152
+ ```
153
+
154
+
155
+
156
+
111
157
 
112
158
  **Tips & Tricks**
113
159
 
@@ -115,7 +161,7 @@ Auto-include pre-build / pre-defined steps. Use a (regular) Module e.g.:
115
161
 
116
162
  ``` ruby
117
163
  module GitHubActions
118
- def setup
164
+ def step_setup
119
165
  # setup ssh
120
166
  ssh_key = ENV['SSH_KEY']
121
167
  ssh_path = File.expand_path( '~/.ssh' )
@@ -133,8 +179,6 @@ module GitHubActions
133
179
 
134
180
  # ...
135
181
  end
136
- # optional - for auto-discovery add a step alias
137
- alias_method :step_setup, :setup
138
182
  end
139
183
  ```
140
184
 
@@ -150,7 +194,54 @@ end
150
194
  Flow::Base.include( GitHubActions )
151
195
  ```
152
196
 
153
- Now all your flows can (re)use `setup` or any other methods you define.
197
+ Now all your flows can (re)use `setup` or any other step methods you define.
198
+
199
+
200
+
201
+
202
+ ## Real World Examples
203
+
204
+ **Collect GitHub Statistics**
205
+
206
+ Use GitHub Actions to collect
207
+ GitHub Statistics via GitHub API calls
208
+ and update the JSON datasets
209
+ in the `/cache.github` repo at the `yorobot` org(anization):
210
+
211
+ ``` ruby
212
+ step :clone do
213
+ Mono.clone( '@yorobot/cache.github' )
214
+ end
215
+
216
+
217
+ step :update do
218
+ Hubba.config.data_dir = Mono.real_path( '@yorobot/cache.github' )
219
+
220
+ username = 'geraldb'
221
+ h = Hubba.reposet( username )
222
+ pp h
223
+
224
+ Hubba.update_stats( h )
225
+ Hubba.update_traffic( h )
226
+ puts "Done."
227
+ end
228
+
229
+
230
+ step :push do
231
+ msg = "auto-update week #{Date.today.cweek}"
232
+
233
+ Mono.open( '@yorobot/cache.github' ) do |proj|
234
+ if proj.changes?
235
+ proj.add( "." )
236
+ proj.commit( msg )
237
+ proj.push
238
+ end
239
+ end
240
+ end
241
+ ```
242
+
243
+ (Sources: [`Flowfile`](https://github.com/yorobot/backup/blob/master/Flowfile.rb), [`workflows/update.yml`](https://github.com/yorobot/backup/blob/master/.github/workflows/update.yml) @ `yorobot/backup`)
244
+
154
245
 
155
246
 
156
247
 
@@ -44,25 +44,70 @@ end # class Step
44
44
 
45
45
 
46
46
  class Base ## base class for flow class (auto)-constructed/build from flowfile
47
- def self.define_step( step )
48
- name = step.names[0]
47
+ def self.define_step( name_or_names, &block )
48
+ names = if name_or_names.is_a?( Array )
49
+ name_or_names
50
+ else
51
+ [name_or_names] ## assume single symbol (name); wrap in array
52
+ end
53
+ names = names.map {|name| name.to_sym } ## make sure we always use symbols
54
+
55
+
56
+ name = names[0]
49
57
  puts "[flow] adding step >#{name}<..."
50
- define_method( name, &step.block )
51
- alias_method( :"step_#{name}", name ) ## (auto-)add step_<name> alias
58
+ define_method( :"step_#{name}", &block )
52
59
 
53
- alt_names = step.names[1..-1]
60
+ alt_names = names[1..-1]
54
61
  alt_names.each do |alt_name|
55
62
  puts "[flow] adding alias >#{alt_name}< for >#{name}<..."
56
- alias_method( alt_name, name )
63
+ alias_method( :"step_#{alt_name}", :"step_#{name}" )
64
+ end
65
+ end # method self.define_step
66
+
67
+
68
+
69
+ ## run step by symbol/name (e.g. step :hello - etc.)
70
+ def step( name )
71
+ name = :"step_#{name}" ## note: make sure we always use symbols
72
+ if respond_to?( name )
73
+ send( name )
74
+ else
75
+ puts "!! ERROR: step definition >#{name}< not found; cannot run/execute - known (defined) steps include:"
76
+ pp self.class.step_methods #=> e.g. [:hello, ...]
77
+ exit 1
57
78
  end
79
+ end # method step
80
+
81
+ def self.step_methods
82
+ names = instance_methods.reduce([]) do |names, name|
83
+ names << $1.to_sym if name =~ /^step_(.+)/
84
+ names
85
+ end
86
+ names
58
87
  end
59
88
  end # class Base
60
89
 
61
90
 
62
91
 
92
+
63
93
  class Flowfile
94
+
95
+ ## find flowfile path by convention
96
+ ## check for name by convention in this order:
97
+ FLOWFILES = ['flowfile', 'Flowfile',
98
+ 'flowfile.rb', 'Flowfile.rb']
99
+ def self.find_file
100
+ FLOWFILES.each do |name|
101
+ return "./#{name}" if File.exist?( "./#{name}" )
102
+ end
103
+
104
+ STDERR.puts "!! ERROR - no flowfile found, sorry - looking for: #{FLOWFILES.join(', ')} in (#{Dir.pwd})"
105
+ exit 1
106
+ end # method self.find_file
107
+
108
+
64
109
  ## convenience method - use like Flowfile.load_file()
65
- def self.load_file( path='./Flowfile' )
110
+ def self.load_file( path=find_file )
66
111
  code = File.open( path, 'r:utf-8' ) { |f| f.read }
67
112
  load( code )
68
113
  end
@@ -76,9 +121,13 @@ class Flowfile
76
121
 
77
122
 
78
123
 
79
- def flow ## build flow class
124
+ def flow
125
+ ## todo/check: always return a new instance why? why not?
126
+ flow_class.new
127
+ end
128
+
129
+ def flow_class
80
130
  @flow_class ||= build_flow_class
81
- @flow_class.new ## todo/check: always return a new instance why? why not?
82
131
  end
83
132
 
84
133
  def build_flow_class
@@ -86,7 +135,7 @@ class Flowfile
86
135
  klass = Class.new( Base )
87
136
 
88
137
  steps.each do |step|
89
- klass.define_step( step )
138
+ klass.define_step( step.names, &step.block )
90
139
  end
91
140
 
92
141
  klass
@@ -106,21 +155,15 @@ class Flowfile
106
155
  @steps << Step.new( name, block )
107
156
  end
108
157
 
109
-
110
158
  def run( name )
111
- name = name.to_sym ## make sure we always use symbols
112
- if flow.respond_to?( name )
113
- flow.send( name )
114
- else
115
- puts "!! ERROR: step definition >#{name}< not found; cannot run/execute - known steps include:"
116
- pp @steps
117
- exit 1
118
- end
159
+ ## todo/check: always return/use a new instance why? why not?
160
+ flow_class.new.step( name )
119
161
  end
120
162
  end # class Flowfile
121
163
 
122
164
 
123
165
 
166
+
124
167
  class Tool
125
168
  def self.main( args=ARGV )
126
169
  options = {}
@@ -128,17 +171,41 @@ class Tool
128
171
  parser.on( '-f FILENAME', '--flowfile FILENAME' ) do |filename|
129
172
  options[:flowfile] = filename
130
173
  end
174
+
175
+ ## note:
176
+ ## you can add many/multiple modules
177
+ ## e.g. -r gitti -r mono etc.
178
+ parser.on( '-r NAME', '--require NAME') do |name|
179
+ options[:requires] ||= []
180
+ options[:requires] << name
181
+ end
131
182
  end.parse!( args )
132
183
 
133
- path = options[:flowfile] || './Flowfile'
184
+
185
+ ## check for any (dynamic/auto) requires
186
+ if options[:requires]
187
+ names = options[:requires]
188
+ names.each do |name|
189
+ ## todo/check: add some error/exception handling here - why? why not?
190
+ puts "[flow] (auto-)require >#{name}<..."
191
+ require( name )
192
+ end
193
+ end
194
+
195
+
196
+ path = options[:flowfile] || Flowfile.find_file
197
+
198
+
199
+ puts "[flow] loading >#{path}<..."
134
200
  flowfile = Flowfile.load_file( path )
135
201
 
202
+
136
203
  ## allow multipe steps getting called - why? why not?
137
204
  ## flow setup clone update etc??
138
205
  args.each do |arg|
139
206
  flowfile.run( arg )
140
207
  end
141
- end
208
+ end # method self.main
142
209
  end # class Tool
143
210
 
144
211
  end # module Flow
@@ -2,7 +2,7 @@ module FlowLite
2
2
 
3
3
  MAJOR = 1 ## todo: namespace inside version or something - why? why not??
4
4
  MINOR = 0
5
- PATCH = 0
5
+ PATCH = 1
6
6
  VERSION = [MAJOR,MINOR,PATCH].join('.')
7
7
 
8
8
  def self.version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flow-lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-25 00:00:00.000000000 Z
11
+ date: 2020-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc