faith 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []