trailblazer-activity 0.3.2 → 0.4.o

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +4 -3
  3. data/CHANGES.md +4 -0
  4. data/lib/trailblazer/activity.rb +82 -140
  5. data/lib/trailblazer/activity/config.rb +37 -0
  6. data/lib/trailblazer/activity/dsl/add_task.rb +22 -0
  7. data/lib/trailblazer/activity/dsl/helper.rb +49 -0
  8. data/lib/trailblazer/activity/implementation/build_state.rb +31 -0
  9. data/lib/trailblazer/activity/implementation/fast_track.rb +14 -0
  10. data/lib/trailblazer/activity/implementation/interface.rb +16 -0
  11. data/lib/trailblazer/activity/implementation/path.rb +55 -0
  12. data/lib/trailblazer/activity/implementation/railway.rb +18 -0
  13. data/lib/trailblazer/activity/{introspection.rb → introspect.rb} +33 -11
  14. data/lib/trailblazer/activity/magnetic.rb +7 -18
  15. data/lib/trailblazer/activity/magnetic/builder.rb +37 -92
  16. data/lib/trailblazer/activity/magnetic/builder/default_normalizer.rb +26 -0
  17. data/lib/trailblazer/activity/magnetic/builder/fast_track.rb +13 -15
  18. data/lib/trailblazer/activity/magnetic/builder/normalizer.rb +105 -0
  19. data/lib/trailblazer/activity/magnetic/builder/path.rb +14 -15
  20. data/lib/trailblazer/activity/magnetic/builder/railway.rb +8 -11
  21. data/lib/trailblazer/activity/magnetic/dsl.rb +4 -1
  22. data/lib/trailblazer/activity/magnetic/finalizer.rb +1 -1
  23. data/lib/trailblazer/activity/magnetic/merge.rb +18 -0
  24. data/lib/trailblazer/activity/present.rb +1 -1
  25. data/lib/trailblazer/activity/schema/dependencies.rb +6 -1
  26. data/lib/trailblazer/activity/state.rb +58 -0
  27. data/lib/trailblazer/activity/structures.rb +1 -2
  28. data/lib/trailblazer/activity/subprocess.rb +6 -3
  29. data/lib/trailblazer/activity/task_builder.rb +38 -0
  30. data/lib/trailblazer/activity/task_wrap.rb +46 -0
  31. data/lib/trailblazer/{wrap → activity/task_wrap}/call_task.rb +3 -3
  32. data/lib/trailblazer/activity/task_wrap/merge.rb +23 -0
  33. data/lib/trailblazer/{wrap → activity/task_wrap}/runner.rb +14 -16
  34. data/lib/trailblazer/{wrap → activity/task_wrap}/trace.rb +3 -3
  35. data/lib/trailblazer/activity/trace.rb +22 -28
  36. data/lib/trailblazer/activity/version.rb +2 -2
  37. data/lib/trailblazer/circuit.rb +7 -5
  38. data/trailblazer-activity.gemspec +2 -1
  39. metadata +39 -14
  40. data/lib/trailblazer/activity/heritage.rb +0 -30
  41. data/lib/trailblazer/activity/magnetic/builder/block.rb +0 -37
  42. data/lib/trailblazer/activity/process.rb +0 -16
  43. data/lib/trailblazer/activity/wrap.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 45961f74078de84b48e1d65403b6924e82fef026
4
- data.tar.gz: 29aab14192b6de4e418ac9668b3aa306c785420f
2
+ SHA256:
3
+ metadata.gz: 7eb2fd05fd42b86db598839e4903e7f81cd44f43f435625a2907c689df522675
4
+ data.tar.gz: f83b35f3c13b44f11f36eec569fbcb008f5681a935ce078316648dd7036a7e88
5
5
  SHA512:
6
- metadata.gz: 0e5ec16c9bbf0c3f7ce34bf2b80d544cc51dd750c21a5f4516413b5ce83121642fa8ad5cf47cd6790168f479a57adcc0252da9c0beafdc82ce0802e1ea213965
7
- data.tar.gz: e38ad33a55650947db2df5aa87b785d78d6c1f92603afcfe26352dfb36f92454a017e5ea08148249afb1524b4fa5464ff1c4f48bc01f0947700619d358f767b6
6
+ metadata.gz: f1b5afb1f62768f177a77dece7954d0251df6f2568373e134aa54aa4535998bba270795ffc200b00bd6b5cb892237452bf0799f492d35cc8ad43fe0e13f83714
7
+ data.tar.gz: 0e6c7a8abb6b7e5db35ac1a154389eed2c6462e6fce1fcd8d502edf4cfd8484037a1c769b096add34a952b74ca1eac4630861d245c4c955d5d8528f343b6d0c7
data/.travis.yml CHANGED
@@ -1,13 +1,14 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.0
4
+ # - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
7
  - 2.3.3
8
- - 2.4.0
8
+ - 2.4.1
9
+ - 2.5.0
9
10
  matrix:
10
11
  include:
11
- - rvm: jruby-9.1.13.0
12
+ - rvm: jruby-9.1.15.0
12
13
  env: JRUBY_OPTS="--profile.api"
13
14
  before_install: gem install bundler
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.4.0
2
+
3
+ * We now use the "Module Subclass" pattern, and activities aren't classes anymore but modules.
4
+
1
5
  # 0.3.2
2
6
 
3
7
  * In the `TaskWrap`, rename `:result_direction` to `:return_signal` and `:result_args` to `:return_args`,
@@ -1,177 +1,119 @@
1
- require "trailblazer/circuit"
1
+ require "trailblazer/activity/version"
2
2
 
3
3
  module Trailblazer
4
- class Activity
5
- module Interface
6
- def decompose # TODO: test me
7
- @process.instance_variable_get(:@circuit).to_fields
8
- end
9
-
10
- def debug # TODO: TEST ME
11
- @debug
12
- end
13
- end
14
-
15
- extend Interface
16
-
17
- require "trailblazer/activity/version"
18
- require "trailblazer/activity/structures"
19
-
20
- require "trailblazer/activity/subprocess"
21
-
22
- require "trailblazer/activity/wrap"
23
- require "trailblazer/wrap/call_task"
24
- require "trailblazer/wrap/trace"
25
- require "trailblazer/wrap/runner"
26
-
27
- require "trailblazer/activity/trace"
28
- require "trailblazer/activity/present"
29
-
4
+ def self.Activity(implementation=Activity::Path, options={})
5
+ Activity.new(implementation, state)
6
+ end
30
7
 
31
- require "trailblazer/activity/magnetic" # the "magnetic" DSL
32
- require "trailblazer/activity/schema/sequence"
8
+ class Activity < Module
9
+ attr_reader :initial_state
33
10
 
34
- require "trailblazer/activity/process"
35
- require "trailblazer/activity/introspection"
11
+ def initialize(implementation, options)
12
+ builder, adds, circuit, outputs, options = BuildState.build_state_for( implementation.config, options)
36
13
 
37
- require "trailblazer/activity/heritage"
14
+ @initial_state = State::Config.build(
15
+ builder: builder,
16
+ options: options,
17
+ adds: adds,
18
+ circuit: circuit,
19
+ outputs: outputs,
20
+ )
38
21
 
39
- def self.call(args, circuit_options={})
40
- @process.( args, circuit_options )
22
+ include *options[:extend] # include the DSL methods.
23
+ include PublicAPI
41
24
  end
42
25
 
43
- #- modelling
44
-
45
- # @private
46
- # DISCUSS: #each instead?
47
- # FIXME: move to Introspection
48
- def self.find(&block)
49
- @process.instance_variable_get(:@circuit).instance_variable_get(:@map).find(&block)
50
- end
51
-
52
- def self.outputs
53
- @outputs
26
+ # Injects the initial configuration into the module defining a new activity.
27
+ def extended(extended)
28
+ super
29
+ extended.instance_variable_set(:@state, initial_state)
54
30
  end
55
31
 
56
- #- DSL part
57
32
 
58
- def self.build(&block)
59
- Class.new(self, &block)
33
+ module Inspect
34
+ def inspect
35
+ "#<Trailblazer::Activity: {#{name || self[:options][:name]}}>"
36
+ end
60
37
  end
61
38
 
62
- private
63
39
 
64
- def self.inherited(subclass)
65
- super
66
- subclass.initialize!(*subclass.config)
67
- heritage.(subclass)
68
- end
69
-
70
- def self.initialize!(builder_class, normalizer)
71
- initialize_activity_dsl!(builder_class, normalizer)
72
- recompile_process!
73
- end
40
+ require "trailblazer/activity/dsl/helper"
41
+ # Helpers such as Path, Output, End to be included into {Activity}.
42
+ module DSLHelper
43
+ extend Forwardable
44
+ def_delegators :@builder, :Path
45
+ def_delegators DSL::Helper, :Output, :End
74
46
 
75
- # builder is stateless, it's up to you to save @adds somewhere.
76
- def self.initialize_activity_dsl!(builder_class, normalizer)
77
- @builder, @adds = builder_class.for( normalizer ) # e.g. Path.for(...) which creates a Builder::Path instance.
78
- @debug = {} # only @adds and @debug are mutable
79
- end
80
-
81
- def self.recompile_process!
82
- @process, @outputs = Recompile.( @adds )
47
+ def Path(*args, &block)
48
+ self[:builder].Path(*args, &block)
49
+ end
83
50
  end
84
51
 
85
- def self.config # FIXME: the normalizer is the same we have in Builder::plan.
86
- return Magnetic::Builder::Path, Magnetic::Builder::DefaultNormalizer.new(plus_poles: Magnetic::Builder::Path.default_plus_poles)
87
- end
52
+ module Accessor
53
+ def []=(*args)
54
+ @state = State::Config.send(:[]=, @state, *args)
55
+ end
88
56
 
89
- # DSL part
90
-
91
- # DISCUSS: make this functions and don't include?
92
- module DSL
93
-
94
- # Create a new method (e.g. Activity::step) that delegates to its builder, recompiles
95
- # the process, etc. Method comes in a module so it can be overridden via modules.
96
- #
97
- # This approach assumes you maintain a @adds and a @debug instance variable. and #heritage
98
- def self.def_dsl!(_name)
99
- Module.new do
100
- define_method(_name) do |*args, &block|
101
- _task(_name, *args, &block) # TODO: similar to Block.
102
- end
103
- end
57
+ def [](*args)
58
+ State::Config[@state, *args]
104
59
  end
60
+ end
105
61
 
106
- private
62
+ # FIXME: still to be decided
63
+ # By including those modules, we create instance methods.
64
+ # Later, this module is `extended` in Path, Railway and FastTrack, and
65
+ # imports the DSL methods as class methods.
66
+ module PublicAPI
67
+ include Accessor
107
68
 
108
- def _task(name, *args, &block)
109
- heritage.record(name, *args, &block)
69
+ require "trailblazer/activity/dsl/add_task"
70
+ include DSL::AddTask
110
71
 
111
- adds, *returned_options = @builder.send(name, *args, &block)
72
+ require "trailblazer/activity/implementation/interface"
73
+ include Activity::Interface # DISCUSS
112
74
 
113
- @adds += adds
114
- @adds.freeze
75
+ include DSLHelper # DISCUSS
115
76
 
116
- recompile_process!
77
+ include Activity::Inspect # DISCUSS
117
78
 
118
- add_introspection!(adds, *returned_options)
79
+ require "trailblazer/activity/magnetic/merge"
80
+ include Magnetic::Merge # Activity#merge!
119
81
 
120
- return adds, returned_options
121
- end
82
+ def call(args, argumenter: [], **circuit_options) # DISCUSS: the argumenter logic might be moved out.
83
+ _, args, circuit_options = argumenter.inject( [self, args, circuit_options] ) { |memo, argumenter| argumenter.(*memo) }
122
84
 
123
- def add_introspection!(adds, task, local_options, *)
124
- @debug[task] = { id: local_options[:id] }.freeze
85
+ self[:circuit].( args, circuit_options.merge(argumenter: argumenter) )
125
86
  end
126
87
  end
88
+ end # Activity
89
+ end
127
90
 
128
- # delegate as much as possible to Builder
129
- # let us process options and e.g. do :id
130
- class << self
131
- extend Forwardable # TODO: test those helpers
132
- def_delegators :@builder, :Path#, :task
133
- end
134
-
135
- extend DSL # _task, :add_introspection
136
- extend DSL.def_dsl!(:task) # define Activity::task.
137
-
138
- extend Heritage::Accessor
91
+ require "trailblazer/circuit"
92
+ require "trailblazer/activity/structures"
93
+ require "trailblazer/activity/config"
139
94
 
95
+ require "trailblazer/activity/implementation/build_state"
96
+ require "trailblazer/activity/implementation/interface"
97
+ require "trailblazer/activity/implementation/path"
98
+ require "trailblazer/activity/implementation/railway"
99
+ require "trailblazer/activity/implementation/fast_track"
140
100
 
141
- # MOVE ME TO ADDS
142
- module Recompile
143
- # Recompile the process and outputs from the {ADDS} instance that collects circuit tasks and connections.
144
- def self.call(adds)
145
- process, end_events = Magnetic::Builder::Finalizer.(adds)
146
- outputs = recompile_outputs(end_events)
101
+ require "trailblazer/activity/task_wrap"
102
+ require "trailblazer/activity/task_wrap/call_task"
103
+ require "trailblazer/activity/task_wrap/trace"
104
+ require "trailblazer/activity/task_wrap/runner"
105
+ require "trailblazer/activity/task_wrap/merge"
147
106
 
148
- return process, outputs
149
- end
107
+ require "trailblazer/activity/trace"
108
+ require "trailblazer/activity/present"
150
109
 
151
- private
110
+ require "trailblazer/activity/introspect"
152
111
 
153
- def self.recompile_outputs(end_events)
154
- ary = end_events.collect do |evt|
155
- [
156
- semantic = evt.instance_variable_get(:@options)[:semantic], # DISCUSS: better API here?
157
- Activity::Output(evt, semantic)
158
- ]
159
- end
160
-
161
- ::Hash[ ary ]
162
- end
163
- end
112
+ # require "trailblazer/activity/heritage"
113
+ require "trailblazer/activity/subprocess"
164
114
 
165
- # TODO: hm
166
- class Railway < Activity
167
- def self.config # FIXME: the normalizer is the same we have in Builder::plan.
168
- return Magnetic::Builder::Railway, Magnetic::Builder::DefaultNormalizer.new(plus_poles: Magnetic::Builder::Railway.default_plus_poles)
169
- end
115
+ require "trailblazer/activity/state"
116
+ require "trailblazer/activity/magnetic" # the "magnetic" DSL
117
+ require "trailblazer/activity/schema/sequence"
170
118
 
171
- extend DSL
172
- extend DSL.def_dsl!(:step)
173
- extend DSL.def_dsl!(:fail)
174
- extend DSL.def_dsl!(:pass)
175
- end
176
- end
177
- end
119
+ require "trailblazer/activity/magnetic/builder/normalizer" # DISCUSS: name and location are odd. This one uses Activity ;)
@@ -0,0 +1,37 @@
1
+ module Trailblazer
2
+ module Activity::State
3
+ # Compile-time
4
+ #
5
+ # DISCUSS: we could replace parts with Hamster::Hash.
6
+ class Config
7
+ def self.build(variables={})
8
+ Hash[ variables.collect { |k,v| [k, v.freeze] } ].freeze
9
+ end
10
+
11
+ def self.[]=(state, *args)
12
+ if args.size == 2
13
+ key, value = *args
14
+
15
+ state = state.merge(key => value)
16
+ else
17
+ directive, key, value = *args
18
+
19
+ state = state.merge( directive => {}.freeze ) unless state.key?(directive)
20
+
21
+ directive_hash = state[directive].merge(key => value)
22
+ state = state.merge( directive => directive_hash.freeze )
23
+ end
24
+
25
+ state
26
+ end
27
+
28
+ def self.[](state, *args)
29
+ directive, key = *args
30
+
31
+ return state[directive] if args.size == 1
32
+ return state[directive][key] if state.key?(directive)
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ class Trailblazer::Activity < Module
2
+ module DSL
3
+ module AddTask
4
+ def add_task!(name, task, options, &block)
5
+ # The beautiful thing about State.add is it doesn't mutate anything.
6
+ # We're changing state here, on the outside, by overriding the ivars.
7
+ # That in turn means, the only mutated entity is this module.
8
+
9
+ _builder, adds, circuit, outputs, options = State.add( self[:builder], self[:adds], name, task, options, &block ) # this could be an extension itself.
10
+
11
+ self[:adds] = adds
12
+ self[:circuit] = circuit
13
+ self[:outputs] = outputs
14
+
15
+ task, local_options = options
16
+
17
+ # {Extension API} call all extensions.
18
+ local_options[:extension].collect { |ext| ext.(self, *options) } if local_options[:extension]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ module Trailblazer
2
+ module Activity::DSL
3
+ # Create a new method (e.g. Activity::step) that delegates to its builder, recompiles
4
+ # the circuit, etc. Method comes in a module so it can be overridden via modules.
5
+ #
6
+ # This approach assumes you maintain a {#add_task!} method.
7
+ def self.def_dsl(_name)
8
+ Module.new do
9
+ define_method(_name) do |task, options={}, &block|
10
+ builder, adds, circuit, outputs, options = add_task!(_name, task, options, &block) # TODO: similar to Block.
11
+ end
12
+ end
13
+ end
14
+
15
+ # Shortcut functions for the DSL. These have no state.
16
+ module Helper
17
+ module_function
18
+
19
+ # Output( Left, :failure )
20
+ # Output( :failure ) #=> Output::Semantic
21
+ def Output(signal, semantic=nil)
22
+ return Activity::Magnetic::DSL::Output::Semantic.new(signal) if semantic.nil?
23
+
24
+ Activity.Output(signal, semantic)
25
+ end
26
+
27
+ def End(name, semantic)
28
+ Activity.End(name, semantic)
29
+ end
30
+
31
+ def Path(normalizer, track_color: "track_#{rand}", end_semantic: :success, **options)
32
+ options = options.merge(track_color: track_color, end_semantic: end_semantic)
33
+
34
+ # Build an anonymous class which will be where the block is evaluated in.
35
+ # We use the same normalizer here, so DSL calls in the inner block have the same behavior.
36
+ path = Module.new do
37
+ extend Activity::Path( options.merge( normalizer: normalizer ) )
38
+ end
39
+
40
+ # this block is called in DSL::ProcessTuples. This could be improved somehow.
41
+ ->(block) {
42
+ path.instance_exec(&block)
43
+
44
+ [ track_color, path ]
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ class Trailblazer::Activity < Module
2
+ module BuildState
3
+ # Compute all objects that need to be passed into the new Activity module.
4
+ # 1. Build the normalizer (unless passed with :normalizer)
5
+ # 2. Build the builder (in State)
6
+ # 3. Let State compute all state variables (that implies recompiling the Process)
7
+ #
8
+ # @return [Builder, Adds, Process, Outputs, remaining options]
9
+ # @api private
10
+ def self.build_state_for(default_options, options)
11
+ options = default_options.merge(options) # TODO: use Variables::Merge() here.
12
+ normalizer, options = build_normalizer(options)
13
+ builder, adds, circuit, outputs, options = build_state(normalizer, options)
14
+ end
15
+
16
+ # Builds the normalizer (to process options in DSL calls) unless {:normalizer} is already set.
17
+ #
18
+ # @api private
19
+ def self.build_normalizer(normalizer_class:, normalizer: false, **options)
20
+ normalizer, options = normalizer_class.build( options ) unless normalizer
21
+
22
+ return normalizer, options
23
+ end
24
+
25
+ def self.build_state(normalizer, builder_class:, builder_options: {}, **options)
26
+ builder, adds, circuit, outputs = State.build(builder_class, normalizer, options.merge(builder_options))
27
+
28
+ return builder, adds, circuit, outputs, options
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ class Trailblazer::Activity < Module
2
+ def self.FastTrack(options={})
3
+ FastTrack.new(FastTrack, options)
4
+ end
5
+
6
+ # Implementation module that can be passed to `Activity[]`.
7
+ class FastTrack < Trailblazer::Activity
8
+ def self.config
9
+ Railway.config.merge(
10
+ builder_class: Magnetic::Builder::FastTrack,
11
+ )
12
+ end
13
+ end
14
+ end