taski 0.1.0 → 0.2.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 +4 -4
- data/LICENSE +21 -0
- data/README.md +299 -31
- data/Steepfile +20 -0
- data/examples/complex_example.rb +109 -0
- data/examples/readme_example.rb +30 -0
- data/lib/taski/dependency_analyzer.rb +162 -0
- data/lib/taski/exceptions.rb +14 -0
- data/lib/taski/reference.rb +40 -0
- data/lib/taski/task/base.rb +60 -0
- data/lib/taski/task/define_api.rb +125 -0
- data/lib/taski/task/dependency_resolver.rb +105 -0
- data/lib/taski/task/exports_api.rb +31 -0
- data/lib/taski/task/instance_management.rb +135 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +35 -150
- data/sig/taski.rbs +60 -2
- metadata +30 -4
data/lib/taski.rb
CHANGED
@@ -1,155 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
module Taski
|
6
|
-
class Reference
|
7
|
-
def initialize(klass)
|
8
|
-
@klass = klass
|
9
|
-
end
|
10
|
-
|
11
|
-
def deref
|
12
|
-
Object.const_get(@klass)
|
13
|
-
end
|
14
|
-
|
15
|
-
def inspect
|
16
|
-
"&#{@klass}"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class Task
|
21
|
-
def self.__resolve__
|
22
|
-
@__resolve__ ||= {}
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.ref(klass)
|
26
|
-
ref = Reference.new(klass)
|
27
|
-
throw :unresolve, ref
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.definition(name, block, **options)
|
31
|
-
@dependencies ||= []
|
32
|
-
@definitions ||= {}
|
33
|
-
|
34
|
-
self.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
35
|
-
def self.#{name}
|
36
|
-
__resolve__[__callee__] ||= false
|
37
|
-
if __resolve__[__callee__]
|
38
|
-
# already resolved
|
39
|
-
else
|
40
|
-
__resolve__[__callee__] = true
|
41
|
-
throw :unresolve, [self, __callee__]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
RUBY
|
45
|
-
|
46
|
-
classes = []
|
47
|
-
loop do
|
48
|
-
klass, task = catch(:unresolve) do
|
49
|
-
block.call
|
50
|
-
nil
|
51
|
-
end
|
52
|
-
|
53
|
-
if klass.nil?
|
54
|
-
classes.each do |task_class|
|
55
|
-
task_class[:klass].class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
56
|
-
__resolve__ = {}
|
57
|
-
RUBY
|
58
|
-
end
|
59
|
-
|
60
|
-
break
|
61
|
-
else
|
62
|
-
classes << { klass:, task: }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
@dependencies += classes
|
67
|
-
@definitions[name] = {block:, options:, classes:}
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.build
|
71
|
-
resolve_dependences.reverse.each do |task_class|
|
72
|
-
task_class.new.build
|
73
|
-
end
|
74
|
-
end
|
3
|
+
require 'set'
|
4
|
+
require 'monitor'
|
75
5
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
def exec_command(command, info = nil, ret = false)
|
83
|
-
puts "exec: #{info}" if info
|
84
|
-
puts command
|
85
|
-
|
86
|
-
if ret
|
87
|
-
ret = `#{command}`.chomp
|
88
|
-
if $?.exited?
|
89
|
-
ret
|
90
|
-
else
|
91
|
-
raise "Failed to execute command: #{command}"
|
92
|
-
end
|
93
|
-
else
|
94
|
-
system command, exception: true
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.refresh
|
99
|
-
# TODO
|
100
|
-
end
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
def self.resolve(queue, resolved)
|
105
|
-
@dependencies.each do |task|
|
106
|
-
if task[:klass].is_a?(Reference)
|
107
|
-
task_class = task[:klass].deref
|
108
|
-
end
|
109
|
-
|
110
|
-
# increase priority
|
111
|
-
if resolved.include?(task[:klass])
|
112
|
-
resolved.delete(task[:klass])
|
113
|
-
end
|
114
|
-
queue << task[:klass]
|
115
|
-
end
|
116
|
-
|
117
|
-
# override
|
118
|
-
self.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
119
|
-
def self.ref(klass)
|
120
|
-
Object.const_get(klass)
|
121
|
-
end
|
122
|
-
RUBY
|
123
|
-
|
124
|
-
@definitions.each do |name, (block, options)|
|
125
|
-
# override
|
126
|
-
self.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
127
|
-
def self.#{name}
|
128
|
-
@__#{name} ||= @definitions[:#{name}][:block].call
|
129
|
-
end
|
130
|
-
RUBY
|
131
|
-
|
132
|
-
self.define_method(name) do
|
133
|
-
unless instance_variable_defined?("@__#{name}")
|
134
|
-
instance_variable_set("@__#{name}", self.class.send(name))
|
135
|
-
end
|
136
|
-
instance_variable_get("@__#{name}")
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
self
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.resolve_dependences
|
144
|
-
queue = [self]
|
145
|
-
resolved = []
|
6
|
+
# Load core components
|
7
|
+
require_relative "taski/version"
|
8
|
+
require_relative "taski/exceptions"
|
9
|
+
require_relative "taski/reference"
|
10
|
+
require_relative "taski/dependency_analyzer"
|
146
11
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
12
|
+
# Load Task class components
|
13
|
+
require_relative "taski/task/base"
|
14
|
+
require_relative "taski/task/exports_api"
|
15
|
+
require_relative "taski/task/define_api"
|
16
|
+
require_relative "taski/task/instance_management"
|
17
|
+
require_relative "taski/task/dependency_resolver"
|
151
18
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
19
|
+
module Taski
|
20
|
+
# Main module for the Taski task framework
|
21
|
+
#
|
22
|
+
# Taski provides a framework for defining and managing task dependencies
|
23
|
+
# with two complementary APIs:
|
24
|
+
# 1. Exports API - Export instance variables as class methods (static dependencies)
|
25
|
+
# 2. Define API - Define lazy-evaluated values with dynamic dependency resolution
|
26
|
+
#
|
27
|
+
# Use Define API when:
|
28
|
+
# - Dependencies change based on runtime conditions
|
29
|
+
# - Environment-specific configurations
|
30
|
+
# - Feature flags determine which classes to use
|
31
|
+
# - Complex conditional logic determines dependencies
|
32
|
+
#
|
33
|
+
# Features:
|
34
|
+
# - Automatic dependency resolution (static and dynamic)
|
35
|
+
# - Static analysis of method dependencies
|
36
|
+
# - Runtime dependency resolution for conditional logic
|
37
|
+
# - Thread-safe task building
|
38
|
+
# - Circular dependency detection
|
39
|
+
# - Memory leak prevention
|
40
|
+
end
|
data/sig/taski.rbs
CHANGED
@@ -1,4 +1,62 @@
|
|
1
1
|
module Taski
|
2
2
|
VERSION: String
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
# Custom exceptions
|
5
|
+
class CircularDependencyError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class TaskAnalysisError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
class TaskBuildError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Reference class for task references
|
15
|
+
class Reference
|
16
|
+
@klass: String
|
17
|
+
|
18
|
+
def initialize: (String klass) -> void
|
19
|
+
def deref: () -> Class
|
20
|
+
def ==: (untyped other) -> bool
|
21
|
+
def inspect: () -> String
|
22
|
+
end
|
23
|
+
|
24
|
+
# Main Task class
|
25
|
+
class Task
|
26
|
+
# Constants
|
27
|
+
THREAD_KEY_SUFFIX: String
|
28
|
+
TASKI_ANALYZING_DEFINE_KEY: Symbol
|
29
|
+
ANALYZED_METHODS: Array[Symbol]
|
30
|
+
|
31
|
+
# Hook methods
|
32
|
+
def self.method_added: (Symbol method_name) -> void
|
33
|
+
|
34
|
+
# Public API methods
|
35
|
+
def self.exports: (*Symbol names) -> void
|
36
|
+
def self.define: (Symbol name, Proc block, **untyped options) -> void
|
37
|
+
def self.build: () -> void
|
38
|
+
def self.clean: () -> void
|
39
|
+
def self.reset!: () -> self
|
40
|
+
def self.refresh: () -> self
|
41
|
+
def self.resolve: (Array[untyped] queue, Array[untyped] resolved) -> self
|
42
|
+
def self.ref: (String klass) -> Reference
|
43
|
+
def self.ensure_instance_built: () -> Task
|
44
|
+
|
45
|
+
# Instance methods
|
46
|
+
def build: () -> void
|
47
|
+
def clean: () -> void
|
48
|
+
|
49
|
+
# Allow dynamic method definitions
|
50
|
+
def method_missing: (Symbol name, *untyped args) ?{ (*untyped) -> untyped } -> untyped
|
51
|
+
def respond_to_missing?: (Symbol name, bool include_private) -> bool
|
52
|
+
|
53
|
+
# Allow dynamic class method definitions
|
54
|
+
def self.method_missing: (Symbol name, *untyped args) ?{ (*untyped) -> untyped } -> untyped
|
55
|
+
def self.respond_to_missing?: (Symbol name, bool include_private) -> bool
|
56
|
+
end
|
57
|
+
|
58
|
+
# Dependency analyzer module
|
59
|
+
module DependencyAnalyzer
|
60
|
+
def self.analyze_method: (Class klass, Symbol method_name) -> Array[Class]
|
61
|
+
end
|
62
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taski
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ahogappa
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
11
|
-
dependencies:
|
10
|
+
date: 2025-06-15 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: prism
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.4'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.4'
|
12
26
|
description: Taski is a Ruby-based task runner currently under development. It allows
|
13
27
|
you to define small, composable tasks along with the outputs they depend on. Taski
|
14
28
|
statically resolves dependencies and executes tasks in the correct topological order,
|
@@ -21,9 +35,21 @@ executables: []
|
|
21
35
|
extensions: []
|
22
36
|
extra_rdoc_files: []
|
23
37
|
files:
|
38
|
+
- LICENSE
|
24
39
|
- README.md
|
25
40
|
- Rakefile
|
41
|
+
- Steepfile
|
42
|
+
- examples/complex_example.rb
|
43
|
+
- examples/readme_example.rb
|
26
44
|
- lib/taski.rb
|
45
|
+
- lib/taski/dependency_analyzer.rb
|
46
|
+
- lib/taski/exceptions.rb
|
47
|
+
- lib/taski/reference.rb
|
48
|
+
- lib/taski/task/base.rb
|
49
|
+
- lib/taski/task/define_api.rb
|
50
|
+
- lib/taski/task/dependency_resolver.rb
|
51
|
+
- lib/taski/task/exports_api.rb
|
52
|
+
- lib/taski/task/instance_management.rb
|
27
53
|
- lib/taski/version.rb
|
28
54
|
- sig/taski.rbs
|
29
55
|
homepage: https://github.com/ahogappa/taski
|
@@ -46,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
72
|
- !ruby/object:Gem::Version
|
47
73
|
version: '0'
|
48
74
|
requirements: []
|
49
|
-
rubygems_version: 3.6.
|
75
|
+
rubygems_version: 3.6.2
|
50
76
|
specification_version: 4
|
51
77
|
summary: A simple yet powerful Ruby task runner with static dependency resolution
|
52
78
|
(in development).
|