caml 0.1.0

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