faith 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f08e57362c103d57c01b70e1e8adc9130a10d3da8368d1dc75c6a875640be7f8
4
+ data.tar.gz: aea9712d13039785bbb16ed4e89e38744e88fc40da7fee5d00883ec2f2065a3c
5
+ SHA512:
6
+ metadata.gz: 18be11a99c1e621aaeeb857cbc14a325f781e22c7ac5fed1c0a723806251b242dab2a104557cd9e1daf5b5c800728fe92f1113af41c178215c12086948fc8edd
7
+ data.tar.gz: b4e1fc73f66274267aba6642999248324eceec81f71fef1e8d9c96f2ce23a31bde947c8241fb662887e3b82f37501e28e3c5d109f43a286cdc5612d992056846
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ sorbet/rbi/hidden-definitions
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.6
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in faith.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ faith (0.1.0)
5
+ docile
6
+ rainbow
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.4.4)
12
+ docile (1.3.2)
13
+ rainbow (3.0.0)
14
+ rake (12.3.3)
15
+ rspec (3.9.0)
16
+ rspec-core (~> 3.9.0)
17
+ rspec-expectations (~> 3.9.0)
18
+ rspec-mocks (~> 3.9.0)
19
+ rspec-core (3.9.2)
20
+ rspec-support (~> 3.9.3)
21
+ rspec-expectations (3.9.2)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.9.0)
24
+ rspec-mocks (3.9.1)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.9.0)
27
+ rspec-support (3.9.3)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ faith!
34
+ rake (~> 12.0)
35
+ rspec (~> 3.0)
36
+
37
+ BUNDLED WITH
38
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Aaron Christiansen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,77 @@
1
+ # Faith
2
+
3
+ **This is a work in progress. Tasks can't be run from a CLI yet, and many
4
+ features are unimplemented.**
5
+
6
+ Faith is an **powerful and extremely versatile task runner**. Using a lovely
7
+ Ruby DSL, you can:
8
+
9
+ - Define named tasks
10
+ - Can be invoked with arguments and options*
11
+ - Assign dependencies between tasks
12
+ - Group tasks together into sensible and organised namespaces
13
+ - Build sequences of tasks which run in order
14
+ - Can either exit or continue if one task fails*
15
+ - Create parallel groups of tasks*
16
+ - Add mixins, which wrap tasks to enhance their environment by running _before_
17
+ and _after_ tasks
18
+
19
+ \* - Not yet implemented
20
+
21
+ ## DSL Example
22
+
23
+ ```ruby
24
+ # A very simple, not-real-world example
25
+
26
+ # Create two mixins, which can provide `number` to a task
27
+ mixin 'a' do
28
+ before do
29
+ provide number: 5
30
+ end
31
+ end
32
+
33
+ mixin 'b' do
34
+ before do
35
+ provide number: 4
36
+ end
37
+ end
38
+
39
+ # Now, create an executable task which uses those provided values
40
+ task 'example', mixins: ['a', 'b'] do
41
+ puts mixins['a'].number * mixins['b'].number # => 20
42
+ end
43
+ ```
44
+
45
+ ## Use Case
46
+
47
+ Faith should make a great starting point for building your own bespoke testing
48
+ framework, or if you feel like you're outgrowing Rake.
49
+
50
+ ## Installation
51
+
52
+ Add this line to your application's Gemfile:
53
+
54
+ ```ruby
55
+ gem 'faith'
56
+ ```
57
+
58
+ And then execute:
59
+
60
+ $ bundle install
61
+
62
+ Or install it yourself as:
63
+
64
+ $ gem install faith
65
+
66
+ ## Name
67
+
68
+ Named after [Faith Connors](https://en.wikipedia.org/wiki/Faith_Connors), a
69
+ **runner** from the _Mirror's Edge_ video games.
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/AaronC81/faith.
74
+
75
+ ## License
76
+
77
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
File without changes
@@ -0,0 +1,30 @@
1
+ require_relative 'lib/faith/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "faith"
5
+ spec.version = Faith::VERSION
6
+ spec.authors = ["Aaron Christiansen"]
7
+ spec.email = ["aaronc20000@gmail.com"]
8
+
9
+ spec.summary = "A versatile task runner"
10
+ spec.description = "A versatile task runner"
11
+ spec.homepage = "https://github.com/AaronC81/faith"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = spec.homepage
17
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "docile"
29
+ spec.add_dependency "rainbow"
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'faith/version'
2
+
3
+ require 'faith/named'
4
+ require 'faith/context'
5
+ require 'faith/mixin'
6
+ require 'faith/mixin_instance'
7
+ require 'faith/task'
8
+ require 'faith/namespace'
9
+ require 'faith/group'
10
+ require 'faith/sequence'
11
+
12
+ require 'faith/dsl'
13
+ require 'faith/output'
@@ -0,0 +1,19 @@
1
+ module Faith
2
+ class Context
3
+ def initialize
4
+ @mixin_instances = []
5
+ @tasks_executed = []
6
+ @output = Output.new
7
+ end
8
+
9
+ attr_accessor :mixin_instances, :tasks_executed, :output
10
+
11
+ def ran?(task)
12
+ tasks_executed.include?(task)
13
+ end
14
+
15
+ def mixins
16
+ mixin_instances.to_h { |x| [x.mixin.name, x] }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,71 @@
1
+ require 'docile'
2
+
3
+ module Faith
4
+ module DSL
5
+ def self.to_root(&block)
6
+ root = Faith::Group.new('root', nil, [])
7
+ Docile.dsl_eval(ChildBuilder.new(root), &block)
8
+ root.resolve_self!
9
+ root
10
+ end
11
+
12
+ def self.validate_name!(name)
13
+ raise ArgumentError, 'names cannot include :' if name.include?(':')
14
+ raise ArgumentError, '\'root\' is a reserved name' if name == 'root'
15
+ end
16
+
17
+ class ChildBuilder
18
+ def initialize(parent)
19
+ @parent = parent
20
+ end
21
+
22
+ def task(name, mixins: [], dependencies: [], &action)
23
+ DSL.validate_name!(name)
24
+
25
+ @parent.children << Task.new(name, @parent, mixins: mixins, dependencies: dependencies, &action)
26
+ end
27
+
28
+ def mixin(name, &block)
29
+ DSL.validate_name!(name)
30
+
31
+ @parent.children << Docile.dsl_eval(MixinBuilder.new(name, @parent), &block).result
32
+ end
33
+
34
+ def group(name, &block)
35
+ DSL.validate_name!(name)
36
+
37
+ group = Group.new(name, @parent, [])
38
+ @parent.children << group
39
+
40
+ Docile.dsl_eval(ChildBuilder.new(group), &block)
41
+ end
42
+
43
+ def sequence(name, &block)
44
+ DSL.validate_name!(name)
45
+
46
+ seq = Sequence.new(name, @parent, [])
47
+ @parent.children << seq
48
+
49
+ Docile.dsl_eval(ChildBuilder.new(seq), &block)
50
+ end
51
+ end
52
+
53
+ class MixinBuilder
54
+ def initialize(name, parent)
55
+ @mixin = Mixin.new(name, parent)
56
+ end
57
+
58
+ def before(&block)
59
+ @mixin.before = block
60
+ end
61
+
62
+ def after(&block)
63
+ @mixin.after = block
64
+ end
65
+
66
+ def result
67
+ @mixin
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ module Faith
2
+ class Group < Namespace
3
+ def initialize(name, parent, children, mixins: [], dependencies: [])
4
+ super(name, parent, children, mixins: mixins, dependencies: dependencies) do
5
+ raise 'cannot run a group'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module Faith
2
+ class Mixin
3
+ def initialize(name, parent, before: nil, after: nil)
4
+ @name = name
5
+ @parent = parent
6
+ @before = before
7
+ @after = after
8
+ end
9
+
10
+ attr_accessor :name, :parent, :before, :after
11
+
12
+ include Named
13
+
14
+ def instantiate(context)
15
+ MixinInstance.new(self)
16
+ end
17
+
18
+ def resolve_self!; end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Faith
2
+ class MixinInstance
3
+ def initialize(mixin, provided: {})
4
+ @mixin = mixin
5
+ @provided = provided
6
+ end
7
+
8
+ attr_accessor :mixin, :provided
9
+
10
+ def method_missing(name, *args, &block)
11
+ return provided[name] if provided.has_key?(name) && args.length.zero? && block.nil?
12
+ super
13
+ end
14
+
15
+ def provide(**items)
16
+ provided.merge! items
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Faith
2
+ module Named
3
+ def root?
4
+ name == 'root'
5
+ end
6
+
7
+ def full_name
8
+ (parent && !parent.root?) ? "#{parent.full_name}:#{name}" : name
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Faith
2
+ class Namespace < Task
3
+ def initialize(name, parent, children, mixins: [], dependencies: [], &action)
4
+ super(name, parent, mixins: mixins, dependencies: dependencies, &action)
5
+ @children = children
6
+ end
7
+
8
+ attr_accessor :children
9
+
10
+ def resolve_self!
11
+ super
12
+ children.each(&:resolve_self!)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ require 'rainbow'
2
+
3
+ module Faith
4
+ class Output
5
+ def initialize
6
+ @indent_level = 0
7
+ end
8
+
9
+ def indent; @indent_level += 1; end
10
+ def dedent; @indent_level -= 1; end
11
+
12
+ def indented(x)
13
+ "#{' ' * @indent_level}#{x}"
14
+ end
15
+
16
+ def run(task)
17
+ puts indented(Rainbow(task.full_name).bold)
18
+ end
19
+
20
+ def dependencies(task)
21
+ puts indented("#{Rainbow("Dependencies of #{task.full_name} -").purple.bold}")
22
+ end
23
+
24
+ def mixin(mixin)
25
+ puts indented("#{Rainbow("Mixin #{mixin.full_name} -").blue.bold}")
26
+ end
27
+
28
+ def sequence(task)
29
+ puts indented("#{Rainbow("Sequence #{task.full_name} -").blue.bold}")
30
+ end
31
+
32
+ def mixin_action(action)
33
+ puts indented("#{Rainbow(action).dark.bold}")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Faith
2
+ class Sequence < Namespace
3
+ def initialize(name, parent, children, mixins: [], dependencies: [])
4
+ s = self
5
+ super(name, parent, children, mixins: mixins, dependencies: dependencies) do |ctx|
6
+ ctx.output.sequence(s)
7
+ ctx.output.indent
8
+ children.each { |child| child.run(ctx) }
9
+ ctx.output.dedent
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,105 @@
1
+ module Faith
2
+ class Task
3
+ def initialize(name, parent, mixins: [], dependencies: [], &action)
4
+ @name = name
5
+ @parent = parent
6
+ @mixins = mixins
7
+ @dependencies = dependencies
8
+ @action = action
9
+ end
10
+
11
+ attr_accessor :name, :parent, :mixins, :dependencies, :action
12
+
13
+ include Named
14
+
15
+ def run(context)
16
+ context.tasks_executed << self
17
+
18
+ # Run dependencies, if not run before
19
+ any_dependencies = dependencies.reject { |dep| context.ran?(dep) }.any?
20
+ if any_dependencies
21
+ context.output.dependencies(self)
22
+ context.output.indent
23
+ end
24
+ dependencies.each do |dep|
25
+ unless context.ran?(dep)
26
+ dep.run(context)
27
+ end
28
+ end
29
+ context.output.dedent if any_dependencies
30
+
31
+ # Instantiate mixins
32
+ new_mixin_instances = mixins.map { |m| m.instantiate(context) }
33
+ new_mixin_instances.each do |m|
34
+ context.output.mixin(m.mixin)
35
+ context.output.indent
36
+ context.output.mixin_action("before")
37
+ m.instance_exec(context, &m.mixin.before) unless m.mixin.before.nil?
38
+ context.mixin_instances << m
39
+ end
40
+
41
+ # Run this task
42
+ context.instance_exec(context, &action)
43
+ context.output.run(self) unless is_a?(Sequence)
44
+
45
+ # Tear down mixins
46
+ new_mixin_instances.each do |m|
47
+ context.output.mixin_action("after")
48
+ m.instance_exec(context, &m.mixin.after) unless m.mixin.after.nil?
49
+ context.output.dedent
50
+ context.mixin_instances.delete(m)
51
+ end
52
+ end
53
+
54
+ def resolve_self!
55
+ @mixins = ensure_all_resolved(@mixins)
56
+ @dependencies = ensure_all_resolved(@dependencies)
57
+ end
58
+
59
+ def ensure_all_resolved(objs)
60
+ objs.map { |obj| ensure_resolved(obj) }
61
+ end
62
+
63
+ def ensure_resolved(obj)
64
+ if obj.is_a?(String)
65
+ resolve(obj)
66
+ elsif obj.is_a?(Task) || obj.is_a?(Mixin)
67
+ obj
68
+ else
69
+ raise "cannot resolve using #{obj} (of type #{obj.class})"
70
+ end
71
+ end
72
+
73
+ def resolve(name_to_resolve)
74
+ parts = name_to_resolve.split(':')
75
+ raise 'empty name' if parts.length.zero?
76
+
77
+ current = self
78
+ until parts.empty?
79
+ current_child = current.child(parts.shift)
80
+
81
+ # If nil, give up finding here
82
+ if current_child.nil?
83
+ if parent.nil?
84
+ raise "could not resolve #{name_to_resolve}"
85
+ else
86
+ return parent.resolve(name_to_resolve)
87
+ end
88
+ end
89
+
90
+ current = current_child
91
+ end
92
+
93
+ # If we actually managed to get parts to be empty, then we found what we were looking for
94
+ current
95
+ end
96
+
97
+ def child(name_to_resolve)
98
+ if is_a?(Namespace)
99
+ children.find { |child| child.name == name_to_resolve }
100
+ else
101
+ nil
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,4 @@
1
+ # typed: strict
2
+ module Faith
3
+ VERSION = "0.1.0"
4
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: faith
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Christiansen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-10-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: docile
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rainbow
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A versatile task runner
42
+ email:
43
+ - aaronc20000@gmail.com
44
+ executables:
45
+ - faith.rb
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".rspec"
51
+ - ".travis.yml"
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - exe/faith.rb
58
+ - faith.gemspec
59
+ - lib/faith.rb
60
+ - lib/faith/context.rb
61
+ - lib/faith/dsl.rb
62
+ - lib/faith/group.rb
63
+ - lib/faith/mixin.rb
64
+ - lib/faith/mixin_instance.rb
65
+ - lib/faith/named.rb
66
+ - lib/faith/namespace.rb
67
+ - lib/faith/output.rb
68
+ - lib/faith/sequence.rb
69
+ - lib/faith/task.rb
70
+ - lib/faith/version.rb
71
+ homepage: https://github.com/AaronC81/faith
72
+ licenses:
73
+ - MIT
74
+ metadata:
75
+ homepage_uri: https://github.com/AaronC81/faith
76
+ source_code_uri: https://github.com/AaronC81/faith
77
+ changelog_uri: https://github.com/AaronC81/faith/CHANGELOG.md
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 2.3.0
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.0.3
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: A versatile task runner
97
+ test_files: []