ruflow 0.0.1 → 0.1.0

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
  SHA256:
3
- metadata.gz: 653e7c74352a1d446f5165fcc8b395313509ffc54849569c2781694674334d44
4
- data.tar.gz: ead4a34b446afb8c18c051f79c9a9abb6f56046d67bcc36f1970bb01fabdc79a
3
+ metadata.gz: fdeec6d4a796f5db914c0eee7f5665936416c281574b6a6f3a53dbe0ac15d8c3
4
+ data.tar.gz: c7598cdfb3279daa47abcc32b7f88e6e95f2295f506512727de8f3393eb4686b
5
5
  SHA512:
6
- metadata.gz: 101a6e4790dd995c1b68f945951cd39fc364df78b8f22d7133d28990feca9313f3c91bae94e33e32efbeb08616f32eb58d957dee7dbdbd92c1a966288f9763b2
7
- data.tar.gz: ed7d81de354fc7253d78bfb20139edcecc21fe1cf0b92ed255e5144450e8ee7010b75e0fee9dfaf0545a3c8c0ad676811ce78a09232276d933728602e24a3c63
6
+ metadata.gz: 802e1ff8608bf668d8a8ee6a6d6ad7dd4a612c5a85a91dcbcea03f1ac2b7e773390d1b38799cd0b70f84dc754699969aac843f4730b54186159ffa5a3bff09e8
7
+ data.tar.gz: cc8ff7550c3f232cb1d33519f98fd4a673a5c97fb01aa6963be2caea6238c0d3cf43939cd1adc0d379ef580c2a77e36877627a6fdcf1f70fdeec211e3f14d8d2
data/.gitignore CHANGED
@@ -13,4 +13,5 @@
13
13
  .ruby-gemset
14
14
  .ruby-version
15
15
  Gemfile.lock
16
- /spec/dumb
16
+ /spec/dumb
17
+ .byebug_history
@@ -1,5 +1,16 @@
1
- require "ruflow/version"
2
1
  require "configurations"
2
+ require 'require_all'
3
+
4
+ require "ruflow/version"
5
+ require "ruflow/type_checker"
6
+ require "ruflow/action"
7
+ require "ruflow/flow"
8
+
9
+ require "ruflow/error/bad_return"
10
+ require "ruflow/error/mismatch_input_type"
11
+ require "ruflow/error/mismatch_output_type"
12
+ require "ruflow/error/mismatch_output_input_type"
13
+ require "ruflow/error/output_port_not_defined"
3
14
 
4
15
  module Ruflow
5
16
  include Configurations
@@ -13,6 +24,9 @@ module Ruflow
13
24
 
14
25
  def setup(&block)
15
26
  Ruflow.configure(&block)
27
+
28
+ autoload_all "#{Dir.pwd}/#{config.components_folder}/actions"
29
+ autoload_all "#{Dir.pwd}/#{config.components_folder}/flows"
16
30
  end
17
31
  end
18
32
  end
@@ -0,0 +1,92 @@
1
+ module Ruflow
2
+ class Action
3
+ class << self
4
+ attr_accessor :options
5
+
6
+ alias_method :set_options, :options=
7
+
8
+ def change_options(_options = {})
9
+ self.options = options.merge(_options)
10
+ end
11
+
12
+ def with_custom_options(_options = {})
13
+ klass = self.clone
14
+ klass.change_options(_options)
15
+ klass
16
+ end
17
+
18
+ def start(param = nil)
19
+ _param = param.nil? ? options[:default_input] : param
20
+
21
+ type_check_input!(_param, input_type)
22
+ output_port_and_value = self.new.start(_param)
23
+
24
+ check_return!(output_port_and_value)
25
+
26
+ output_port, value = output_port_and_value
27
+
28
+ check_output_port_is_defined!(output_port)
29
+
30
+ output_type = options[:output][output_port]
31
+
32
+ type_check_output!(value, output_type)
33
+
34
+ [output_port, value]
35
+ end
36
+
37
+ def input_type
38
+ options[:input]
39
+ end
40
+
41
+ def options
42
+ @options || ::Ruflow::Action.options
43
+ end
44
+
45
+ private
46
+
47
+ def type_check_input!(value, input_type)
48
+ if TypeChecker.is_invalid?(value, type: input_type)
49
+ raise Error::MismatchInputType.new(value, input_type)
50
+ end
51
+ end
52
+
53
+ def check_return!(return_value)
54
+ if return_value.class != Array || return_value.first.class != Symbol
55
+ raise Error::BadReturn.new(return_value)
56
+ end
57
+ end
58
+
59
+ def check_output_port_is_defined!(output_port)
60
+ _output_port = options[:output][output_port]
61
+
62
+ if _output_port.nil? || _output_port.empty?
63
+ raise Error::OutputPortNotDefined.new(_output_port)
64
+ end
65
+ end
66
+
67
+ def type_check_output!(value, output_type)
68
+ if TypeChecker.is_invalid?(value, type: output_type)
69
+ raise Error::MismatchOutputType.new(value, output_type)
70
+ end
71
+ end
72
+ end
73
+
74
+ set_options(
75
+ default_input: nil,
76
+ input: '*',
77
+ output: {
78
+ ok: '*'
79
+ }
80
+ )
81
+
82
+ def start(value = nil)
83
+ raise NotImplementedError, 'Overwrite instance method start'
84
+ end
85
+
86
+ protected
87
+
88
+ def options
89
+ self.class.options
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,9 @@
1
+ module Ruflow
2
+ module Error
3
+ class BadReturn < StandardError
4
+ def initialize(return_value)
5
+ super("Expected start to return [:<<output_port>>, <<value>>], but returned #{return_value}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Ruflow
2
+ module Error
3
+ class MismatchInputType < StandardError
4
+ def initialize(value, expect_type)
5
+ super("Expected INPUT as #{expect_type}, but received #{value.class}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Ruflow
2
+ module Error
3
+ class MismatchOutputInputType < StandardError
4
+ attr_reader :errors
5
+
6
+ def initialize(errors, msg="Mismatches found in: ")
7
+ @errors = Array(errors)
8
+ super(msg + format_errors)
9
+ end
10
+
11
+ private
12
+
13
+ def format_errors
14
+ @errors.map { |e| "ACTION_ID=#{e[:from_action_id]} to ACTION_ID=#{e[:to_action_id]} mismatch type on port #{e[:port]} (#{e[:from]} to #{e[:to]})" }
15
+ .join(', ')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Ruflow
2
+ module Error
3
+ class MismatchOutputType < StandardError
4
+ def initialize(value, expect_type)
5
+ super("Expected OUTPUT to be a #{expect_type}, but was #{value.class}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Ruflow
2
+ module Error
3
+ class OutputPortNotDefined < StandardError
4
+ def initialize(return_value)
5
+ super("Expected start method to return [:<<output_port>>, <<value>>], but returned #{return_value}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,75 @@
1
+ module Ruflow
2
+ class Flow < Action
3
+
4
+ def start(param)
5
+ action = self.class.start_action
6
+ value = param
7
+
8
+ while action[:output_to]
9
+ output_port, value = action[:klass].start(value)
10
+
11
+ action = self.class.actions[action[:output_to][output_port]]
12
+ end
13
+
14
+ action[:klass].start(value)
15
+ end
16
+
17
+ class << self
18
+ attr_accessor :actions, :start_action_id
19
+
20
+ alias_method :set_actions, :actions=
21
+ alias_method :set_start_action_id, :start_action_id=
22
+
23
+ def check_actions!
24
+ raise NotImplementedError, 'actions must be defined using set_actions({})' if actions.nil?
25
+
26
+ raise NotImplementedError, 'start_action_id must be defined using set_start_action_id(Integer)' if start_action_id.nil?
27
+
28
+ raise NotImplementedError, 'actions must be a Hash' if not(actions.is_a?(Hash))
29
+
30
+ raise NotImplementedError, 'start_action not found, change the start_action_id' if start_action.nil?
31
+
32
+ if (actions_with_error = actions_without_klass).any?
33
+ raise NotImplementedError, "actions id=#{actions_with_error.keys.join(', ')} must have value as a Hash and define a 'klass:' key"
34
+ end
35
+
36
+ if (actions_with_error = actions_mismatch_output_input_type).any?
37
+ raise Error::MismatchOutputInputType.new(actions_with_error)
38
+ end
39
+ end
40
+
41
+ def start
42
+ check_actions!
43
+ super(nil)
44
+ end
45
+
46
+ def start_action
47
+ actions[start_action_id]
48
+ end
49
+
50
+ private
51
+
52
+ def actions_without_klass
53
+ actions.select { |_, a| not(a.is_a?(Hash)) || a[:klass].nil? }
54
+ end
55
+
56
+ def actions_with_output_to
57
+ actions.select { |_, a| a[:output_to] }
58
+ end
59
+
60
+ def actions_mismatch_output_input_type
61
+ actions_with_output_to.map do |action_id, action|
62
+
63
+ action[:output_to].map do |port, next_action_id|
64
+ action_input_type = actions[next_action_id][:klass].options[:input]
65
+ action_output_type = action[:klass].options[:output][port]
66
+
67
+ if TypeChecker.incompatible_types?(action_input_type, action_output_type)
68
+ {from_action_id: action_id, to_action_id: next_action_id, from: action_output_type, to: action_input_type, port: port}
69
+ end
70
+ end
71
+ end.flatten.compact
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,14 +1,27 @@
1
1
  require_relative 'setup'
2
+ require_relative '../../ruflow'
2
3
 
3
4
  module Ruflow
4
5
  module Tasks
5
6
  class Base < Thor
6
- desc "new [PROJECT_NAME]", "generate a new project"
7
+ desc "new [PROJECT_NAME]", "Generate a new project"
7
8
  def new(project_name)
8
9
  Ruflow::Tasks::Setup.start([project_name])
9
10
  end
10
11
 
11
- desc "setup", "generate all files and folder required"
12
+ desc "start [FLOW_CLASS_NAME]", "Start a flow"
13
+ def start(flow_klass_name)
14
+ _file_path = "#{Dir.pwd}/ruflow_config"
15
+
16
+ if File.exist?("#{_file_path}.rb")
17
+ require _file_path
18
+ Kernel.const_get(flow_klass_name).start
19
+ else
20
+ puts "ruflow_config.rb not found on #{Dir.pwd}"
21
+ end
22
+ end
23
+
24
+ desc "setup", "Generate all files and folder required"
12
25
  def setup
13
26
  Ruflow::Tasks::Setup.start(['.'])
14
27
  end
@@ -0,0 +1,33 @@
1
+ module Ruflow
2
+ module TypeChecker
3
+ def self.incompatible_types?(type, compare_type)
4
+ !compatible_types?(type, compare_type)
5
+ end
6
+
7
+ def self.compatible_types?(type, compare_type)
8
+ return true if compare_type.include? '*'
9
+
10
+ compare_types = compare_type.split('|')
11
+
12
+ type.split('|').any? { |t| compare_types.include?(t) }
13
+ end
14
+
15
+ def self.is_invalid?(value, type:)
16
+ !is_valid?(value, type: type)
17
+ end
18
+
19
+ def self.is_valid?(value, type:)
20
+ return true if type.include? '*'
21
+
22
+ types = type.split('|').map { |t| get_constant(t) }.flatten
23
+
24
+ types.any? { |t| value.is_a?(t) }
25
+ end
26
+
27
+ private
28
+
29
+ def self.get_constant(type)
30
+ type == 'Boolean' ? [TrueClass, FalseClass] : [Kernel.const_get(type)]
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module Ruflow
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -21,9 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.add_dependency "configurations", "~> 2.2.0"
24
- spec.add_dependency "thor", "~> 0.20.0"
24
+ spec.add_dependency "thor", "~> 0.20.0"
25
+ spec.add_dependency "require_all", "~> 1.5.0"
25
26
 
26
27
  spec.add_development_dependency "bundler", "~> 1.16"
27
28
  spec.add_development_dependency "rake", "~> 10.0"
28
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
+ spec.add_development_dependency "byebug"
29
31
  end
@@ -0,0 +1,21 @@
1
+ module Actions
2
+ class Printer < ::Ruflow::Action
3
+ set_options(
4
+ default_input: '',
5
+ input: 'String',
6
+ output: {
7
+ ok: 'String'
8
+ }
9
+ )
10
+
11
+ def self.with_custom_options(can_print:, text:)
12
+ super(can_print: can_print, text: text)
13
+ end
14
+
15
+ def start(text)
16
+ puts text if options[:can_print]
17
+
18
+ [:ok, text + options[:text]]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module Flows
2
+ class HelloWorld < ::Ruflow::Flow
3
+ set_actions({
4
+ 1 => { klass: ::Actions::Printer.with_custom_options(can_print: false, text: 'Hello'), output_to: { ok: 2 } },
5
+ 2 => { klass: ::Actions::Printer.with_custom_options(can_print: false, text: 'Hello'), output_to: { ok: 3 } },
6
+ 3 => { klass: ::Actions::Printer.with_custom_options(can_print: false, text: 'Again'), output_to: { ok: 4 } },
7
+ 4 => { klass: ::Actions::Printer.with_custom_options(can_print: true, text: 'World') }
8
+ })
9
+
10
+ set_start_action_id(1)
11
+ end
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - victor95pc
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-08 00:00:00.000000000 Z
11
+ date: 2018-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: configurations
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.20.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: require_all
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: Framework to create flow-based programs using Ruby.
84
112
  email:
85
113
  - victorpalomocastro@gmail.com
@@ -108,12 +136,22 @@ files:
108
136
  - bin/thor
109
137
  - exe/ruflow
110
138
  - lib/ruflow.rb
139
+ - lib/ruflow/action.rb
140
+ - lib/ruflow/error/bad_return.rb
141
+ - lib/ruflow/error/mismatch_input_type.rb
142
+ - lib/ruflow/error/mismatch_output_input_type.rb
143
+ - lib/ruflow/error/mismatch_output_type.rb
144
+ - lib/ruflow/error/output_port_not_defined.rb
145
+ - lib/ruflow/flow.rb
111
146
  - lib/ruflow/tasks/base.rb
112
147
  - lib/ruflow/tasks/setup.rb
148
+ - lib/ruflow/type_checker.rb
113
149
  - lib/ruflow/version.rb
114
150
  - ruflow.gemspec
115
151
  - setup_files/Gemfile
116
152
  - setup_files/components/.gitkeep
153
+ - setup_files/components/actions/printer.rb
154
+ - setup_files/components/flows/hello_world.rb
117
155
  - setup_files/ruflow_config.rb
118
156
  homepage: https://github.com/victor95pc/ruflow
119
157
  licenses: []