flow-lite 1.0.0 → 1.0.1

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: 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