caml 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c8112aee1b07f561a5a61568f3d53d7c4bf002de6eb011be5e835490c404cb0f
4
+ data.tar.gz: a72ec8bf5815f84abb80b585c6ab0d1d84802b23e91672a47844c16cf2894f46
5
+ SHA512:
6
+ metadata.gz: 113daadc8195e7ea3667d3ac463455e3e9c2f18ff022f3ee030ce68672c14e4ce022b91e16f479b12a6060c2aa626ab8bf16596af29d8e2cd018a0c4fc4ef9c1
7
+ data.tar.gz: d9d5127a760273c578b486b4754e97d24b278e215f9d9edc3a1ac730ec24fc5a9ae6add0525e183c821ed0c65528d955c136360f58ae51668f2fe49025587a92
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2020 Ian Johnson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # 🐪 caml
2
+
3
+ > Build CLI apps with YAML
4
+
5
+ `caml` allows you to build command line applications using declarative yaml.
6
+ `caml` aims to be like `make`, but by using descriptive, declarative yaml.
7
+
8
+ ## Usage
9
+
10
+ Running the command without any arguments displays the commands defined in the `caml.yaml` file:
11
+
12
+ ```sh
13
+ bin/caml
14
+ ```
15
+
16
+ ## Declaring commands
17
+
18
+ `caml` reads a file called `caml.yaml` in the current directory and converts those commands into a unified CLI command.
19
+
20
+ The basic structure is to have a `command`, which has a `desc` and an `execute` for the bash command to execute.
21
+
22
+ ```yaml
23
+ command:
24
+ desc: Command description
25
+ execute: script.sh
26
+ ```
27
+
28
+ This yaml will create the following command:
29
+
30
+ ```yaml
31
+ bin/caml command # Command description
32
+ ```
33
+
34
+ And it will run any bash command defined.
35
+
36
+ Arguments may be added under `args` in a nested fashion as displayed below.
37
+
38
+ ```yaml
39
+ command:
40
+ args:
41
+ one:
42
+ desc: First argument
43
+ type: string
44
+ two:
45
+ desc: Second argument
46
+ type: string
47
+ ```
48
+
49
+ ## Examples
50
+
51
+ ```yaml
52
+ build:
53
+ desc: Build our project
54
+ execute: make
55
+ clean:
56
+ desc: Clean our project
57
+ execute: make clean
58
+ ```
59
+
60
+ ```yaml
61
+ build:
62
+ desc: Bundle
63
+ execute: bundle install
64
+ migrate:
65
+ desc: Migrate the test database
66
+ execute: rails db:migrate RAILS_ENV=test
67
+ test:
68
+ desc: Run tests
69
+ execute: rspec
70
+ ```
data/bin/caml ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require_relative '../lib/caml/caml'
5
+
6
+ # TODO:
7
+ # x Yaml
8
+ # x Metaprogramming
9
+ # _ Thor commands, options, arguments, etc.
10
+ # _ Add bash and ruby commands
11
+ # _ Turn into gem
12
+ # _ Distribute via CMM gem server
13
+ # _ Make some noise
14
+ # _ Make it better with Rust
15
+ # _ Distribute a release on GHE
16
+ # _ Make some more noise
17
+
18
+
19
+ class CamlCli < Thor
20
+ def self.load
21
+ Caml::Config.new.directives.each do |entry|
22
+ directive = build_directive(entry)
23
+ args = build_args(directive['args'])
24
+ opts = build_opts(directive['opts'])
25
+ command = build_command(directive.merge({'args' => args, 'opts' => opts}))
26
+ puts command
27
+ puts ''
28
+ class_eval command.to_s
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def self.build_directive(entry)
35
+ entry.last.merge({'name' => entry.first, 'args' => entry.last['args'] || [], 'opts' => entry.last['opts'] || []})
36
+ end
37
+
38
+ def self.build_args(args)
39
+ args.reject { |arg| arg.empty? }
40
+ .map { |name, arg| arg.merge({'name' => name}) }
41
+ .map { |arg| Caml::Argument.new(arg) }
42
+ end
43
+
44
+ def self.build_opts(opts)
45
+ opts.reject { |opt| opt.empty? }
46
+ .map { |name, opt| opt.merge({'name' => name}) }
47
+ .map { |opt| Caml::Option.new(opt) }
48
+ end
49
+
50
+ def self.build_command(directive)
51
+ Caml::Command.new(directive)
52
+ end
53
+
54
+ no_commands do
55
+ def execute
56
+ successful = system yield
57
+ exit successful
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ CamlCli.load
64
+ CamlCli.start(ARGV)
data/lib/caml/caml.rb ADDED
@@ -0,0 +1,107 @@
1
+ require 'safe_yaml/load'
2
+
3
+ module Caml
4
+ # def self.wrap(object)
5
+ # if object.nil?
6
+ # []
7
+ # elsif object.respond_to?(:to_ary)
8
+ # object.to_ary || [object]
9
+ # else
10
+ # [object]
11
+ # end
12
+ # end
13
+
14
+ class Config
15
+ def initialize
16
+ # Recursively load (prompt to init if it doesn't exist)
17
+ SafeYAML::OPTIONS[:default_mode] = :safe
18
+ @config = YAML.load_file(File.join(Dir.getwd, 'caml.yaml'))
19
+ end
20
+
21
+ def directives
22
+ @config
23
+ end
24
+
25
+ def to_s
26
+ inspect
27
+ end
28
+ end
29
+
30
+ class Command
31
+ attr_reader :name, :desc, :aliases, :args, :opts, :execute
32
+
33
+ def initialize(options = {})
34
+ @name = options['name']
35
+ @desc = options['desc']
36
+ @aliases = options['aliases']
37
+ @args = options['args']
38
+ @opts = options['opts']
39
+ @execute = options['execute']
40
+ end
41
+
42
+ def dispatcher
43
+ if opts.empty?
44
+ executor
45
+ else
46
+ first_clause = "if options[:#{opts.first.name.to_sym}]\nexecute { \"#{opts.first.execute}\" }\n"
47
+ # else_clause = directive.execute.nil? ? "#\n" : "else\nexecute { \"#{wrap(directive.execute).join(';')}\" }\nend"
48
+ # clauses = directive.options.drop(1).map { |option| "elsif options[:#{option.name.to_sym}]\nexecute { \"#{wrap(option.execute).join(';')}\" }\n" }.join
49
+ # dispatcher = first_clause + clauses + else_clause
50
+ puts first_clause
51
+ executor
52
+ end
53
+ end
54
+
55
+ def executor
56
+ if execute.respond_to?(:join)
57
+ <<-EOS
58
+ execute do
59
+ <<-COMMANDS
60
+ #{execute.join("\n")}
61
+ COMMANDS
62
+ end
63
+ EOS
64
+ else
65
+ "execute { \"#{execute}\" }\n"
66
+ end
67
+ end
68
+
69
+ def to_s
70
+ descriptor = "desc '#{name}', '#{desc}'\n"
71
+ options = opts.empty? ? '' : opts.join("\n") + "\n"
72
+ signature = "def #{name}\n" # TODO: args
73
+ close_scope = "end\n"
74
+ descriptor + options + signature + executor + close_scope
75
+ end
76
+ end
77
+
78
+ class Option
79
+ attr_reader :name, :type, :desc, :aliases, :execute
80
+
81
+ def initialize(options = {})
82
+ @name = options['name']
83
+ @type = options['type']
84
+ @desc = options['desc']
85
+ @aliases = options['aliases']
86
+ @execute = options['execute']
87
+ end
88
+
89
+ def to_s
90
+ "option :#{name}, type: :#{type}, desc: '#{desc}'"
91
+ end
92
+ end
93
+
94
+ class Argument
95
+ attr_reader :name, :type, :desc, :value
96
+
97
+ def initialize(options ={})
98
+ @name = options['name']
99
+ @desc = options['desc']
100
+ @type = options['type']
101
+ end
102
+
103
+ def to_s
104
+ inspect
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,9 @@
1
+ require 'caml/caml'
2
+
3
+ module Caml
4
+ describe Caml do
5
+ it 'works' do
6
+ expect(1).to eq(1)
7
+ end
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: caml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ian Johnson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: "# \U0001F42A caml\n\n> Build CLI apps with YAML\n\n`caml` allows you
28
+ to build command line applications using declarative yaml.\n`caml` aims to be like
29
+ `make`, but by using descriptive, declarative yaml.\n\n## Usage\n\nRunning the command
30
+ without any arguments displays the commands defined in the `caml.yaml` file:\n\n```sh\nbin/caml\n```\n\n##
31
+ Declaring commands\n\n`caml` reads a file called `caml.yaml` in the current directory
32
+ and converts those commands into a unified CLI command.\n\nThe basic structure is
33
+ to have a `command`, which has a `desc` and an `execute` for the bash command to
34
+ execute.\n\n```yaml\ncommand:\n desc: Command description\n execute: script.sh\n```\n\nThis
35
+ yaml will create the following command:\n\n```yaml\nbin/caml command # Command description\n```\n\nAnd
36
+ it will run any bash command defined.\n\nArguments may be added under `args` in
37
+ a nested fashion as displayed below.\n\n```yaml\ncommand:\n args:\n one:\n desc:
38
+ First argument\n type: string\n two:\n desc: Second argument\n type:
39
+ string\n```\n\n## Examples\n\n```yaml\nbuild:\n desc: Build our project\n execute:
40
+ make\nclean:\n desc: Clean our project\n execute: make clean\n```\n\n```yaml\nbuild:\n
41
+ \ desc: Bundle\n execute: bundle install\nmigrate:\n desc: Migrate the test database\n
42
+ \ execute: rails db:migrate RAILS_ENV=test\ntest:\n desc: Run tests\n execute:
43
+ rspec\n```\n"
44
+ email: tacoda@hey.com
45
+ executables:
46
+ - caml
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - LICENSE
51
+ - README.md
52
+ - bin/caml
53
+ - lib/caml/caml.rb
54
+ - spec/caml/caml_spec.rb
55
+ homepage: https://github.com/tacoda/caml
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.9'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.2.22
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Build CLI apps using YAML
78
+ test_files:
79
+ - spec/caml/caml_spec.rb