justprep 1.0.1 → 1.2.4
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/Gemfile.lock +1 -1
- data/README.md +17 -8
- data/bin/justprep +2 -2
- data/justfile +4 -24
- data/justprep.gemspec +9 -11
- data/lib/justprep/common/constants.crb +53 -0
- data/lib/justprep/common/error_messages.crb +71 -0
- data/lib/justprep/common/expand_file_path.crb +18 -0
- data/lib/justprep/common/generate_module_tasks.crb +61 -0
- data/lib/justprep/common/handle_command_line_parameters.crb +38 -0
- data/lib/justprep/common/include_content_from.crb +26 -0
- data/lib/justprep/common/just_find_it.crb +18 -0
- data/lib/justprep/common/replacement_for_module_line.crb +54 -0
- data/lib/justprep/common/usage.crb +71 -0
- data/lib/justprep/crystal_methods.rb +26 -0
- data/lib/justprep/version.rb +1 -1
- data/lib/justprep.rb +88 -155
- metadata +18 -14
- data/prototype.rb +0 -125
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa284b4a811b6a6482c55b8fbb60e13e20833583d92d7b5d43672bf0dd9178a1
|
4
|
+
data.tar.gz: 592f588b3f165fa25e4fb0309f6763ceb625d8859cb6e1d80709a98bb3bd0eb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5d250ba9b75361d51c0c756772a846199f8486b4ce2772b0c2d60e76550e9f3bde3b59ac2b3d77d249594bb30246a89de64d97e26e4089ba3dd711bacf2535d
|
7
|
+
data.tar.gz: 6dc5e9a051e6326a95decf12dae092fe9ca59d97f25344009818f784fdf47f12960ccbe007a921d46b12ff4264b6536b0a5257e5e92f7bda4dd708aafd9e27c7
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,19 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# `justprep`
|
2
2
|
|
3
|
-
|
3
|
+
Just a CLI pre-processor tool for task runners like "just" my current favorite.
|
4
4
|
|
5
|
-
|
5
|
+
This directory is the codebase for the Ruby gem implementation. It also contains the common directory where \*.crb files are kept. These are the files that are shared between this Ruby gem implementation and the Crystal implementation.
|
6
6
|
|
7
|
-
|
7
|
+
### Installation for the Ruby version
|
8
8
|
|
9
|
-
|
9
|
+
gem install justprep
|
10
10
|
|
11
|
-
|
11
|
+
### Installation for the Crystal version
|
12
12
|
|
13
|
-
|
13
|
+
brew install --build-from-source MadBomber/tap/justprep
|
14
|
+
|
15
|
+
### Documentation
|
16
|
+
|
17
|
+
Since this capability is implemented in both Ruby and Crystal there is only one set of documentation. Both implementations act the same way. See the [repository's Wiki](https://github.com/MadBomber/justprep/wiki) for details.
|
18
|
+
|
19
|
+
|
20
|
+
### Contributing
|
14
21
|
|
15
22
|
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/justprep.
|
16
23
|
|
24
|
+
If you have a different CLI task runner than what justprep currently supports, let me know so we can add it to the support list.
|
25
|
+
|
17
26
|
## License
|
18
27
|
|
19
|
-
|
28
|
+
justprep is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/justprep
CHANGED
data/justfile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# github.com/MadBomber/justprep/**/ruby/justfile
|
2
2
|
#
|
3
|
-
# gem install bump
|
4
3
|
|
5
4
|
set positional-arguments := true
|
6
5
|
|
@@ -14,6 +13,10 @@ set positional-arguments := true
|
|
14
13
|
just -l --list-prefix 'just ' --list-heading ''
|
15
14
|
echo
|
16
15
|
|
16
|
+
# Run the minitest examples on the Ruby code
|
17
|
+
test: build
|
18
|
+
rake test
|
19
|
+
|
17
20
|
|
18
21
|
# Build the current gem
|
19
22
|
@build:
|
@@ -24,26 +27,3 @@ set positional-arguments := true
|
|
24
27
|
@install:
|
25
28
|
rake install:local
|
26
29
|
|
27
|
-
|
28
|
-
#################################################
|
29
|
-
## Recipes that deal with the source code version
|
30
|
-
## Version manager is handled by the "bump" gem
|
31
|
-
|
32
|
-
# Set the version: major . minor . patch
|
33
|
-
@set version:
|
34
|
-
bump set {{version}} --no-commit --replace-in ../crystal/version.cr
|
35
|
-
|
36
|
-
|
37
|
-
# Show current version
|
38
|
-
@show:
|
39
|
-
bump current
|
40
|
-
|
41
|
-
|
42
|
-
# Bump the level: major . minor . patch
|
43
|
-
bump level='patch':
|
44
|
-
#!/bin/bash
|
45
|
-
if [[ "{{level}}" =~ ^(major|minor|patch)$ ]]; then
|
46
|
-
bump {{level}} --no-commit --replace-in ../crystal/version.cr
|
47
|
-
else
|
48
|
-
echo "ERROR: level must be one of: major, minor, patch"
|
49
|
-
fi
|
data/justprep.gemspec
CHANGED
@@ -1,25 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
load "lib/justprep/common/constants.crb"
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "justprep"
|
7
|
-
spec.version =
|
7
|
+
spec.version = VERSION
|
8
8
|
spec.authors = ["Dewayne VanHoozer"]
|
9
9
|
spec.email = ["dvanhoozer@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "
|
11
|
+
spec.summary = "Just a pre-processor for CLI task runners like 'just'"
|
12
12
|
spec.description = <<~EOS
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
been process a new "justfile" is created which can then be used by
|
19
|
-
the 'just' tool.
|
13
|
+
justprep is a CLI tool implemented as a Ruby gem AND a
|
14
|
+
compiled Crystal binary. It allows a task file to be
|
15
|
+
auto-generated from seperate source files that contain
|
16
|
+
inclusionary keywords such as include, import, require
|
17
|
+
and with.
|
20
18
|
EOS
|
21
19
|
|
22
|
-
spec.homepage = "http://github.com/MadBomber/justprep
|
20
|
+
spec.homepage = "http://github.com/MadBomber/justprep"
|
23
21
|
spec.license = "MIT"
|
24
22
|
spec.required_ruby_version = ">= 2.4.0"
|
25
23
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
VERSION = "1.2.4"
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# define class variables used for configuration
|
6
|
+
# This helps Crystal know what the type of the varibles are.
|
7
|
+
|
8
|
+
@@justprep_for = "String"
|
9
|
+
@@justprep_module_keyword = "String"
|
10
|
+
@@justprep_keywords = ["String", "String"]
|
11
|
+
@@justprep_filename_in = "String"
|
12
|
+
@@justprep_filename_out = "String"
|
13
|
+
@@filename_option = "String"
|
14
|
+
|
15
|
+
|
16
|
+
# defining all these instance methods for Ruby's unit tests
|
17
|
+
|
18
|
+
def justprep_for ; @@justprep_for end
|
19
|
+
def justprep_module_keyword; @@justprep_module_keyword end
|
20
|
+
def justprep_keywords ; @@justprep_keywords end
|
21
|
+
def justprep_filename_in ; @@justprep_filename_in end
|
22
|
+
def justprep_filename_out ; @@justprep_filename_out end
|
23
|
+
def filename_option ; @@filename_option end
|
24
|
+
|
25
|
+
|
26
|
+
def using_just?
|
27
|
+
"just" == @@justprep_for
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Sets the configuration class variables from their cooresponding
|
32
|
+
# system environment variables. Any configuration coming from the
|
33
|
+
# command-line parameters are set in the handle_command_line_parameters()
|
34
|
+
# method.
|
35
|
+
#
|
36
|
+
def set_configuration
|
37
|
+
@@justprep_for = ENV.fetch("JUSTPREP_FOR", "just")
|
38
|
+
@@justprep_module_keyword = ENV.fetch("JUSTPREP_MODULE_KEYWORD", "module")
|
39
|
+
@@justprep_keywords = ENV.fetch("justprep_keywords", "import include require with").split
|
40
|
+
|
41
|
+
if using_just?
|
42
|
+
@@justprep_filename_in = ENV.fetch("JUSTPREP_FILENAME_IN", "main.just")
|
43
|
+
@@justprep_filename_out = ENV.fetch("JUSTPREP_FILENAME_OUT", "justfile")
|
44
|
+
@@filename_option = "-f"
|
45
|
+
|
46
|
+
else
|
47
|
+
@@justprep_filename_in = ENV.fetch("JUSTPREP_FILENAME_IN")
|
48
|
+
@@justprep_filename_out = ENV.fetch("JUSTPREP_FILENAME_OUT")
|
49
|
+
@@filename_option = ""
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end # class Justprep
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# common/error_messages.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# Parameters:
|
6
|
+
# line_number .. Integer (zero-based index)
|
7
|
+
# a_line ....... String
|
8
|
+
#
|
9
|
+
# Returns:
|
10
|
+
# nil
|
11
|
+
#
|
12
|
+
def error_file_does_not_exist(line_number, a_line)
|
13
|
+
STDERR.puts
|
14
|
+
STDERR.puts "ERROR: File Does Not Exist"
|
15
|
+
|
16
|
+
# Crystal types thinks line_number can be nil or Int32
|
17
|
+
line_out = sprintf("% d ", line_number.nil? ? 0 : line_number)
|
18
|
+
STDERR.puts (" "*line_out.size)+"|"
|
19
|
+
STDERR.puts "#{line_out}| #{a_line}"
|
20
|
+
STDERR.print (" "*line_out.size)+"|"
|
21
|
+
|
22
|
+
x = a_line.index(" ")
|
23
|
+
|
24
|
+
if a_line.starts_with?(@@justprep_module_keyword.to_s)
|
25
|
+
x = a_line.index(" ", x.nil? ? 0 : x + 1) # because Crystal thinks x could be nil
|
26
|
+
end
|
27
|
+
|
28
|
+
begin_filename = x.nil? ? a_line.size + 2 : x + 2
|
29
|
+
end_filename = a_line.size
|
30
|
+
len_filename = end_filename - begin_filename + 1
|
31
|
+
|
32
|
+
len_filename = 13 if len_filename < 0
|
33
|
+
|
34
|
+
STDERR.puts (" "*begin_filename) + ("^"*len_filename)
|
35
|
+
STDERR.puts
|
36
|
+
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def error_syntax(line_number, a_line)
|
42
|
+
STDERR.puts
|
43
|
+
STDERR.puts "ERROR: Syntax Problem"
|
44
|
+
|
45
|
+
# Crystal types thinks line_number can be nil or Int32
|
46
|
+
line_out = sprintf("% d ", line_number.nil? ? 0 : line_number)
|
47
|
+
STDERR.puts (" "*line_out.size)+"|"
|
48
|
+
STDERR.puts "#{line_out}| #{a_line}"
|
49
|
+
STDERR.print (" "*line_out.size)+"| "
|
50
|
+
STDERR.puts "^"*(a_line.size)
|
51
|
+
STDERR.puts
|
52
|
+
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def error_keyword_conflict
|
58
|
+
comma_space = ", "
|
59
|
+
STDERR.puts "
|
60
|
+
|
61
|
+
ERROR: There is a conflict between the environment variables
|
62
|
+
$JUSTPREP_MODULE_KEYWORD _cannot_ be in $JUSTPREP_KEYWORDS
|
63
|
+
|
64
|
+
$JUSTPREP_KEYWORDS => #{@@justprep_keywords.join(comma_space)}
|
65
|
+
$JUSTPREP_MODULE_KEYWORD => #{@@justprep_module_keyword}
|
66
|
+
|
67
|
+
"
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
end # class Justprep
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# common/expand_file_path.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# use an external shell to expand system environment variables
|
6
|
+
def expand_file_path(a_path_string)
|
7
|
+
a_path_string = a_path_string.strip
|
8
|
+
|
9
|
+
if a_path_string.to_s.starts_with? "~"
|
10
|
+
a_path_string = "${HOME}" + a_path_string.to_s[1, a_path_string.to_s.size-1]
|
11
|
+
end
|
12
|
+
|
13
|
+
a_path_string = `echo "#{a_path_string}"`.chomp
|
14
|
+
|
15
|
+
return a_path_string
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class Justprep
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# .../ruby/lib/justprep/common/generate_module_tasks.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# Given an Array of Strings representing the fake
|
6
|
+
# module names it returns a String to be appended
|
7
|
+
# to the generated justfile.
|
8
|
+
#
|
9
|
+
# Input:
|
10
|
+
# module_names .... Array(String) fake module names
|
11
|
+
#
|
12
|
+
# Output:
|
13
|
+
# tasks ... String
|
14
|
+
#
|
15
|
+
def generate_module_tasks(module_names)
|
16
|
+
if self.using_just?
|
17
|
+
tasks = create_just_tasks(module_names)
|
18
|
+
else
|
19
|
+
tasks = "# Do not know how to make modules for #{@@justprep_for}"
|
20
|
+
end
|
21
|
+
|
22
|
+
return tasks
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def create_just_tasks(module_names)
|
27
|
+
tasks = ""
|
28
|
+
|
29
|
+
module_names.each do |mod_name|
|
30
|
+
tasks += "
|
31
|
+
|
32
|
+
# Module #{mod_name}
|
33
|
+
@#{mod_name} what='' args='':
|
34
|
+
#{@@justprep_for} #{@@filename_option} {{module_#{mod_name}}} {{what}} {{args}}
|
35
|
+
|
36
|
+
"
|
37
|
+
end
|
38
|
+
|
39
|
+
return tasks
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def create_run_tasks(module_names)
|
44
|
+
tasks = ""
|
45
|
+
|
46
|
+
module_names.each do |mod_name|
|
47
|
+
tasks += "
|
48
|
+
|
49
|
+
##
|
50
|
+
# Module #{mod_name}
|
51
|
+
# Encapsulates additional tasks
|
52
|
+
#{mod_name}:
|
53
|
+
#{JUSTPREP_FOR} #{FILENAME_OPTION} ${module_#{mod_name}} ${@}
|
54
|
+
|
55
|
+
"
|
56
|
+
end
|
57
|
+
|
58
|
+
return tasks
|
59
|
+
end
|
60
|
+
|
61
|
+
end # class Justprep
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# common/handle_command_line_parameters.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# take care of ARGV
|
6
|
+
#
|
7
|
+
# Returns
|
8
|
+
# nil when there are no command line parameters
|
9
|
+
# otherwise it terminates the process
|
10
|
+
#
|
11
|
+
def handle_command_line_parameters
|
12
|
+
# When true, header/footer wrappers around include content are excluded
|
13
|
+
@@no_brag = false
|
14
|
+
|
15
|
+
if ARGV.size > 0
|
16
|
+
ARGV.each do |param|
|
17
|
+
if "--version" == param
|
18
|
+
puts "jusrprep v#{VERSION} (#{IMPLEMENTATION})"
|
19
|
+
exit(1)
|
20
|
+
elsif ["-h", "--help"].includes?(param)
|
21
|
+
usage
|
22
|
+
exit(1)
|
23
|
+
elsif "--no-brag" == param
|
24
|
+
@@no_brag = true
|
25
|
+
else
|
26
|
+
STDERR.puts "justprep does not support: #{param}"
|
27
|
+
exit(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def no_brag?
|
35
|
+
@@no_brag
|
36
|
+
end
|
37
|
+
|
38
|
+
end # class Justprep
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# .../ruby/lib/justprep/common/def include_content_from.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# single-level inclusion
|
6
|
+
#
|
7
|
+
# Input:
|
8
|
+
# out_file .......... A File pointer for String output
|
9
|
+
# module_filename ... String The name of the file to be included
|
10
|
+
#
|
11
|
+
# Output:
|
12
|
+
# nil .... This is a function without specific return value
|
13
|
+
#
|
14
|
+
def include_content_from(out_file, module_filename)
|
15
|
+
out_file.puts "\n# >>> #{module_filename}" unless no_brag?
|
16
|
+
|
17
|
+
File.read_lines(module_filename).each do |m_line|
|
18
|
+
out_file.puts m_line
|
19
|
+
end
|
20
|
+
|
21
|
+
out_file.puts "# <<< #{module_filename}\n" unless no_brag?
|
22
|
+
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
end # class Justprep
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# common/just_find_it.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# look for first occurace of mainfile
|
6
|
+
# returns nil when none are found.
|
7
|
+
def just_find_it(here = FileUtils.pwd)
|
8
|
+
mainfile_path = here + "/" + @@justprep_filename_in.to_s
|
9
|
+
return mainfile_path if File.exists?(mainfile_path)
|
10
|
+
|
11
|
+
parts = here.to_s.split("/")
|
12
|
+
parts.pop
|
13
|
+
|
14
|
+
return nil if parts.empty?
|
15
|
+
return just_find_it(parts.join('/'))
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class Justprep
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# .../ruby/lig/justprep/common/replacement_for_module_line.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
# Inserts the module_name into the Array of module_names
|
6
|
+
# Returns a string that defines the variable for the path to the module
|
7
|
+
#
|
8
|
+
# This method replaces a source line that looks like this:
|
9
|
+
#
|
10
|
+
# module aaa path/to/modules/justfile
|
11
|
+
#
|
12
|
+
# with a line that looks like this:
|
13
|
+
#
|
14
|
+
# module_aaa := "path/to/modules/justfile"
|
15
|
+
#
|
16
|
+
# where "aaa" is the module name.
|
17
|
+
#
|
18
|
+
# Limitations:
|
19
|
+
#
|
20
|
+
# module_name can not have a space. Only :alphanumberic: characters
|
21
|
+
# and the underscore character are valid.
|
22
|
+
#
|
23
|
+
# The "path/to/modules/justfile" must exist. Otherwise an error
|
24
|
+
# message is generated.
|
25
|
+
#
|
26
|
+
# Input:
|
27
|
+
# line_numer .... Integer the line number in the source file
|
28
|
+
# a_string ...... String the line from the source file
|
29
|
+
#
|
30
|
+
# Output:
|
31
|
+
# an Array(String) of size 2 where
|
32
|
+
# .first is the fake module_name
|
33
|
+
# .last is the replacement string that defines the module variable
|
34
|
+
#
|
35
|
+
def replacement_for_module_line(line_number, a_string)
|
36
|
+
parts = a_string.split(" ")
|
37
|
+
|
38
|
+
if parts.size < 3
|
39
|
+
error_syntax(line_number, a_string)
|
40
|
+
exit(1)
|
41
|
+
end
|
42
|
+
|
43
|
+
module_name = parts[1]
|
44
|
+
path_to_module = parts[2..].join(" ")
|
45
|
+
|
46
|
+
unless File.exists?(path_to_module)
|
47
|
+
error_file_does_not_exist(line_number, a_string)
|
48
|
+
exit(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
return [module_name, "module_#{module_name} := \"#{path_to_module}\""]
|
52
|
+
end
|
53
|
+
|
54
|
+
end # class Justprep
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# common/usage.crb
|
2
|
+
|
3
|
+
class Justprep
|
4
|
+
|
5
|
+
def usage
|
6
|
+
usage_text = "
|
7
|
+
justprep v#{VERSION} (#{IMPLEMENTATION})
|
8
|
+
|
9
|
+
Just a pre-processor to CLI task runners such as 'just'
|
10
|
+
By Dewayne VanHoozer <dvanhoozer@gmail.com>
|
11
|
+
|
12
|
+
USAGE:
|
13
|
+
justprep [flags]
|
14
|
+
justprep && #{@@justprep_for}
|
15
|
+
|
16
|
+
FLAGS:
|
17
|
+
--version Shows the current version
|
18
|
+
-h, --help Displays this usage message
|
19
|
+
--no-brag Do not add header/footer around included content
|
20
|
+
|
21
|
+
DESCRIPTION:
|
22
|
+
Looks for a file named #{@@justprep_filename_in} in the current
|
23
|
+
directory hierarchy. If found it replaces all lines that
|
24
|
+
have the keywords (#{@@justprep_keywords.join(", ")}) followed
|
25
|
+
by a file path with the contents of the specified file.
|
26
|
+
|
27
|
+
if it finds a line that begins with the module keyword
|
28
|
+
(#{@@justprep_module_keyword}) in sets up a fake module
|
29
|
+
system consistent with the target CLI task runner #{@@justprep_for}.
|
30
|
+
|
31
|
+
SYSTEM ENVIRONMENT VARIABLES:
|
32
|
+
Default / Current Value
|
33
|
+
JUSTPREP_FOR ............ 'just'
|
34
|
+
'#{@@justprep_for}'
|
35
|
+
|
36
|
+
JUSTPREP_FILENAME_IN .... 'main.just'
|
37
|
+
'#{@@justprep_filename_in}'
|
38
|
+
|
39
|
+
JUSTPREP_FILENAME_OUT ... 'justfile'
|
40
|
+
'#{@@justprep_filename_out}'
|
41
|
+
|
42
|
+
JUSTPREP_KEYWORDS ....... 'import include require with'
|
43
|
+
'#{@@justprep_keywords.join(' ')}'
|
44
|
+
|
45
|
+
JUSTPREP_MODULE_KEYWORD . 'module'
|
46
|
+
'#{@@justprep_module_keyword}'
|
47
|
+
|
48
|
+
DOCUMENTATION:
|
49
|
+
A full set of documentation can be found in the project's
|
50
|
+
wiki: https://github.com/MadBomber/justprep/wiki
|
51
|
+
|
52
|
+
SUGGESTION:
|
53
|
+
Create an alias for your command shell. For example
|
54
|
+
alias jj='justprep && just'
|
55
|
+
|
56
|
+
THANKS TO:
|
57
|
+
Casey Rodarmor <casey@rodarmor.com>
|
58
|
+
for Just because just is just a handy utility with just an
|
59
|
+
odd name but an extreamly useful product. :)
|
60
|
+
|
61
|
+
Greg Lutostanski <greg.luto@gmail.com>
|
62
|
+
for the homebrew formula and the github actions to compile
|
63
|
+
a new Crystal release.
|
64
|
+
|
65
|
+
"
|
66
|
+
puts usage_text
|
67
|
+
|
68
|
+
return usage_text
|
69
|
+
end
|
70
|
+
|
71
|
+
end # class Justprep
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# common/crystal_methods.rb
|
2
|
+
|
3
|
+
# Monkey oatch Ruby classes to match method names
|
4
|
+
# used by Crystal
|
5
|
+
|
6
|
+
# TODO: find other classes in which Ruby/Crystal differ
|
7
|
+
|
8
|
+
module Enumerable
|
9
|
+
alias_method :includes?, :include?
|
10
|
+
end
|
11
|
+
|
12
|
+
class Pathname
|
13
|
+
alias_method :exists?, :exist?
|
14
|
+
end
|
15
|
+
|
16
|
+
class String
|
17
|
+
alias_method :starts_with?, :start_with?
|
18
|
+
alias_method :ends_with?, :end_with?
|
19
|
+
alias_method :includes?, :include?
|
20
|
+
end
|
21
|
+
|
22
|
+
class File
|
23
|
+
class << self
|
24
|
+
alias_method :read_lines, :readlines
|
25
|
+
end
|
26
|
+
end
|
data/lib/justprep/version.rb
CHANGED
data/lib/justprep.rb
CHANGED
@@ -10,185 +10,118 @@
|
|
10
10
|
#
|
11
11
|
# variable name default value
|
12
12
|
# --------------------- -------------
|
13
|
-
#
|
14
|
-
#
|
13
|
+
# JUSTPREP_FOR ............ 'just'
|
14
|
+
# JUSTPREP_FILENAME_IN ... 'main.just'
|
15
|
+
# JUSTPREP_FILENAME_OUT ... 'justfile'
|
15
16
|
# JUSTPREP_KEYWORDS ... 'import include require with'
|
17
|
+
# JUSTPREP_MODULE_KEYWORD . 'module'
|
18
|
+
#
|
19
|
+
# NOTE:
|
20
|
+
# JUSTPREP_KEYWORDS ** CANNOT ** include the value for
|
21
|
+
# JUSTPREP_MODULE_KEYWORD
|
16
22
|
#
|
17
23
|
|
18
|
-
|
19
|
-
require_relative "justprep/version"
|
20
|
-
|
21
|
-
module Justprep
|
22
|
-
class << self
|
23
|
-
JUSTPREP_FILENAME_IN = ENV.fetch('JUSTPREP_FILENAME_IN', 'main.just')
|
24
|
-
JUSTPREP_FILENAME_OUT = ENV.fetch('JUSTPREP_FILENAME_OUT', 'justfile')
|
25
|
-
JUSTPREP_KEYWORDS = ENV.fetch('JUSTPREP_KEYWORDS', 'import include require with').split
|
24
|
+
IMPLEMENTATION = "Ruby"
|
26
25
|
|
26
|
+
require "fileutils"
|
27
|
+
require "pathname"
|
28
|
+
require_relative "justprep/crystal_methods"
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
# The common directory contains files which are usable in
|
31
|
+
# both the Ruby gem and compiled Crystal implementations
|
32
|
+
# The files have the extension ".crb"
|
33
|
+
#
|
34
|
+
COMMON_DIR = Pathname.new(__FILE__) + '../justprep/common'
|
35
|
+
|
36
|
+
# Loading these common methods as global kernel-level
|
37
|
+
load COMMON_DIR + "constants.crb"
|
38
|
+
load COMMON_DIR + "error_messages.crb"
|
39
|
+
load COMMON_DIR + "expand_file_path.crb"
|
40
|
+
load COMMON_DIR + "handle_command_line_parameters.crb"
|
41
|
+
load COMMON_DIR + "just_find_it.crb"
|
42
|
+
load COMMON_DIR + "usage.crb"
|
43
|
+
load COMMON_DIR + "generate_module_tasks.crb"
|
44
|
+
load COMMON_DIR + "replacement_for_module_line.crb"
|
45
|
+
load COMMON_DIR + "include_content_from.crb"
|
46
|
+
|
47
|
+
class Justprep
|
48
|
+
attr_accessor :module_names
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
set_configuration # sets class vars from envars
|
52
|
+
handle_command_line_parameters # may terminate the process
|
53
|
+
@module_names = []
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Main function called from executable
|
58
|
+
def execute
|
59
|
+
# SMELL: for some reason the crystal_methods alias_method of
|
60
|
+
# includes? for include? is not working.
|
61
|
+
|
62
|
+
if @@justprep_keywords.include?(@@justprep_module_keyword)
|
63
|
+
error_keyword_conflict
|
64
|
+
exit(1)
|
65
|
+
end
|
31
66
|
|
32
|
-
|
33
|
-
modules << text.select{|x| x.start_with?("#{keyword} ") || x.strip == keyword}
|
34
|
-
end
|
67
|
+
in_filename = just_find_it
|
35
68
|
|
36
|
-
|
69
|
+
if in_filename.nil?
|
70
|
+
STDERR.puts "WARNING: $JUSTPREP_FILENAME_IN Not Found: #{@@justprep_filename_in}"
|
71
|
+
exit(0)
|
37
72
|
end
|
38
73
|
|
74
|
+
out_filename = File.dirname(in_filename) + "/" + @@justprep_filename_out
|
39
75
|
|
40
|
-
|
41
|
-
|
42
|
-
content = []
|
43
|
-
content << "\n# >>> #{file_path}"
|
44
|
-
content << file_path.readlines.map{|x| x.chomp} # TODO: support recursion??
|
45
|
-
content << "# <<< #{file_path}\n"
|
76
|
+
in_file = File.open(in_filename, "r")
|
77
|
+
out_file = File.open(out_filename, "w")
|
46
78
|
|
47
|
-
|
48
|
-
end
|
79
|
+
line_number = 0
|
49
80
|
|
81
|
+
in_file.readlines.map{|x| x.chomp}.each do |a_line|
|
82
|
+
line_number += 1
|
50
83
|
|
51
|
-
|
52
|
-
def just_find_it(here=Pathname.pwd)
|
53
|
-
mainfile = here + JUSTPREP_FILENAME_IN
|
54
|
-
return mainfile if mainfile.exist?
|
55
|
-
return nil if here == here.parent
|
56
|
-
return just_find_it(here.parent)
|
57
|
-
end
|
58
|
-
|
84
|
+
parts = a_line.to_s.split(" ")
|
59
85
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
a_path_string = "${HOME}" + a_path_string[1, a_path_string.size-1]
|
86
|
+
if 0 == parts.size
|
87
|
+
out_file.puts
|
88
|
+
next
|
64
89
|
end
|
65
90
|
|
66
|
-
|
91
|
+
# NOTE: Leading spaces are not allowed. The keywords
|
92
|
+
# MUST be complete left-justified.
|
93
|
+
#
|
94
|
+
if @@justprep_keywords.include?(parts.first.downcase)
|
95
|
+
out_file.puts "# #{a_line}" unless no_brag?
|
67
96
|
|
68
|
-
|
69
|
-
end
|
97
|
+
glob_filename = expand_file_path(parts[1..parts.size].join(" "))
|
70
98
|
|
71
|
-
|
72
|
-
def usage
|
73
|
-
puts <<~EOS
|
74
|
-
justprep v#{VERSION} (ruby)
|
75
|
-
A pre-processor to the just command line utility
|
76
|
-
By Dewayne VanHoozer <dvanhoozer@gmail.com>
|
77
|
-
|
78
|
-
USAGE:
|
79
|
-
justprep [flags] && just
|
80
|
-
|
81
|
-
FLAGS:
|
82
|
-
--version Shows the current version
|
83
|
-
-h, --help Displays this usage message
|
84
|
-
|
85
|
-
DESCRIPTION:
|
86
|
-
Looks for a file named #{JUSTPREP_FILENAME_IN} in the current
|
87
|
-
directory hierarchy. If found it replaces all lines that
|
88
|
-
have the keywords (#{JUSTPREP_KEYWORDS.join(", ")}) followed
|
89
|
-
by file path with the contents of the specified file.
|
90
|
-
|
91
|
-
SYSTEM ENVIRONMENT VARIABLES:
|
92
|
-
Default Value
|
93
|
-
JUSTPREP_FILENAME_IN .... main.just
|
94
|
-
JUSTPREP_FILENAME_OUT ... justfile
|
95
|
-
JUSTPREP_KEYWORDS ....... 'import include require with'
|
96
|
-
|
97
|
-
SUGGESTION:
|
98
|
-
Create an alias for your command shell. For example
|
99
|
-
alias jj='justprop && just'
|
100
|
-
|
101
|
-
THANKS TO:
|
102
|
-
Casey Rodarmor <casey@rodarmor.com>
|
103
|
-
Just because just is just a handy utility with just an odd name. :)
|
104
|
-
|
105
|
-
EOS
|
106
|
-
end
|
99
|
+
module_filenames = Dir.glob(glob_filename)
|
107
100
|
|
101
|
+
if 0 == module_filenames.size
|
102
|
+
error_file_does_not_exist(line_number, a_line)
|
103
|
+
exit(1)
|
104
|
+
end
|
108
105
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
ARGV.each do |param|
|
113
|
-
if "--version" == param
|
114
|
-
puts "jusrprep v#{VERSION} (ruby)"
|
115
|
-
elsif ["-h", "--help"].include?(param)
|
116
|
-
usage
|
106
|
+
module_filenames.each do |module_filename|
|
107
|
+
if File.exist?(module_filename)
|
108
|
+
include_content_from(out_file, module_filename)
|
117
109
|
else
|
118
|
-
|
110
|
+
error_file_does_not_exist(line_number, a_line)
|
119
111
|
exit(1)
|
120
112
|
end
|
121
113
|
end
|
114
|
+
elsif @@justprep_module_keyword == parts.first.downcase
|
115
|
+
result_array = replacement_for_module_line(line_number, a_line)
|
116
|
+
@module_names << result_array.first
|
117
|
+
out_file.puts result_array.last
|
118
|
+
else
|
119
|
+
out_file.puts a_line
|
122
120
|
end
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
|
-
# Main function called from executable
|
127
|
-
def execute
|
128
|
-
handle_command_line_parameters
|
129
|
-
|
130
|
-
mainfile = just_find_it
|
131
|
-
|
132
|
-
if mainfile.nil?
|
133
|
-
STDERR.puts "WARNING: JUSTPREP_FILENAME_IN Not Found: #{JUSTPREP_FILENAME_IN}"
|
134
|
-
exit(0)
|
135
|
-
end
|
136
|
-
|
137
|
-
basefile = mainfile.parent + JUSTPREP_FILENAME_OUT
|
138
|
-
|
139
|
-
text = mainfile.readlines.map{|x| x.chomp} # drop the line ending from each line
|
140
|
-
|
141
|
-
modules = find_modules text
|
142
|
-
|
143
|
-
if modules.empty?
|
144
|
-
basefile.write text
|
145
|
-
exit(0)
|
146
|
-
end
|
147
|
-
|
148
|
-
modules.each do |a_line|
|
149
|
-
an_index = text.index a_line
|
150
|
-
begin_filename = a_line.index(' ')
|
121
|
+
end # in_file.readlines ...
|
151
122
|
|
152
|
-
|
153
|
-
module_filename = ""
|
154
|
-
else
|
155
|
-
module_filename = a_line[begin_filename, a_line.size - begin_filename].chomp.strip
|
156
|
-
end
|
157
|
-
|
158
|
-
if module_filename.empty?
|
159
|
-
STDERR.puts "ERROR: No path/to/file was provided"
|
160
|
-
line_out = sprintf('% d ', an_index+1)
|
161
|
-
STDERR.puts (" "*line_out.size)+"|"
|
162
|
-
STDERR.puts "#{line_out}| #{a_line}"
|
163
|
-
STDERR.print (" "*line_out.size)+"|"
|
164
|
-
STDERR.puts (" "*(a_line.size+2)) + "^"
|
165
|
-
exit(1)
|
166
|
-
end
|
167
|
-
|
168
|
-
if module_filename.include?('~') || module_filename.include?('$')
|
169
|
-
module_filename = expand_file_path(module_filename)
|
170
|
-
end
|
171
|
-
|
172
|
-
module_path = Pathname.new(module_filename)
|
173
|
-
|
174
|
-
if module_path.relative?
|
175
|
-
module_path = mainfile.parent + module_path
|
176
|
-
end
|
177
|
-
|
178
|
-
if module_path.exist?
|
179
|
-
text[an_index] = include_content_from(module_path)
|
180
|
-
else
|
181
|
-
STDERR.puts "ERROR: File Does Not Exist - #{module_path}"
|
182
|
-
line_out = sprintf('% d ', an_index+1)
|
183
|
-
STDERR.puts (" "*line_out.size)+"|"
|
184
|
-
STDERR.puts "#{line_out}| #{a_line}"
|
185
|
-
STDERR.print (" "*line_out.size)+"|"
|
186
|
-
STDERR.puts (" "*(a_line.index(module_filename)+1)) + "^"
|
187
|
-
exit(1)
|
188
|
-
end
|
189
|
-
end # modules.each do |a_line|
|
123
|
+
out_file.puts generate_module_tasks(@module_names)
|
190
124
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
end # module Justprep
|
125
|
+
out_file.close
|
126
|
+
end # def
|
127
|
+
end # class Justprep
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: justprep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dewayne VanHoozer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bump
|
@@ -24,14 +24,9 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
description:
|
28
|
-
allows a
|
29
|
-
that
|
30
|
-
and with. These keywords are followed by a path to a file. If the
|
31
|
-
file exists, the contents of the file are inserted into the file
|
32
|
-
at the position of the keyword command. After all keywords have
|
33
|
-
been process a new "justfile" is created which can then be used by
|
34
|
-
the 'just' tool.
|
27
|
+
description: "justprep is a CLI tool implemented as a Ruby gem AND a \ncompiled Crystal
|
28
|
+
binary. It allows a task file to be \nauto-generated from seperate source files
|
29
|
+
that contain \ninclusionary keywords such as include, import, require \nand with.\n"
|
35
30
|
email:
|
36
31
|
- dvanhoozer@gmail.com
|
37
32
|
executables:
|
@@ -50,9 +45,18 @@ files:
|
|
50
45
|
- justfile
|
51
46
|
- justprep.gemspec
|
52
47
|
- lib/justprep.rb
|
48
|
+
- lib/justprep/common/constants.crb
|
49
|
+
- lib/justprep/common/error_messages.crb
|
50
|
+
- lib/justprep/common/expand_file_path.crb
|
51
|
+
- lib/justprep/common/generate_module_tasks.crb
|
52
|
+
- lib/justprep/common/handle_command_line_parameters.crb
|
53
|
+
- lib/justprep/common/include_content_from.crb
|
54
|
+
- lib/justprep/common/just_find_it.crb
|
55
|
+
- lib/justprep/common/replacement_for_module_line.crb
|
56
|
+
- lib/justprep/common/usage.crb
|
57
|
+
- lib/justprep/crystal_methods.rb
|
53
58
|
- lib/justprep/version.rb
|
54
|
-
|
55
|
-
homepage: http://github.com/MadBomber/justprep/tree/main/ruby
|
59
|
+
homepage: http://github.com/MadBomber/justprep
|
56
60
|
licenses:
|
57
61
|
- MIT
|
58
62
|
metadata:
|
@@ -72,8 +76,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
76
|
- !ruby/object:Gem::Version
|
73
77
|
version: '0'
|
74
78
|
requirements: []
|
75
|
-
rubygems_version: 3.
|
79
|
+
rubygems_version: 3.3.18
|
76
80
|
signing_key:
|
77
81
|
specification_version: 4
|
78
|
-
summary:
|
82
|
+
summary: Just a pre-processor for CLI task runners like 'just'
|
79
83
|
test_files: []
|
data/prototype.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
# frozen_string_literal: true
|
4
|
-
# warn_indent: true
|
5
|
-
##########################################################
|
6
|
-
###
|
7
|
-
## File: justprep.rb
|
8
|
-
## Desc: A preprocessor for justfiles using "main.just"
|
9
|
-
## Looks for keywords: import include require with
|
10
|
-
## followed by a file name or path.
|
11
|
-
##
|
12
|
-
## It looks for a file "main.just" in the current directory.
|
13
|
-
## If it does not exist, does nothing. Otherwise it reviews
|
14
|
-
## the file for the KEYWORDS. When found it inserts the
|
15
|
-
## content of the specified file into that position. The
|
16
|
-
## final text is written out to the "justfile" for processing
|
17
|
-
## with the "just" tool.
|
18
|
-
##
|
19
|
-
## There is NO ERROR checking. including file names/paths
|
20
|
-
## are assume to have to space characters.
|
21
|
-
##
|
22
|
-
## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
|
23
|
-
#
|
24
|
-
|
25
|
-
KEYWORDS = %w[ import include require with ]
|
26
|
-
BASEFILE = 'justfile'
|
27
|
-
MAINFILE = 'main.just'
|
28
|
-
|
29
|
-
require 'pathname'
|
30
|
-
|
31
|
-
######################################################
|
32
|
-
# Local methods
|
33
|
-
|
34
|
-
# review the text looking for module references
|
35
|
-
def find_modules(text)
|
36
|
-
modules = []
|
37
|
-
|
38
|
-
KEYWORDS.each do |keyword|
|
39
|
-
modules << text.select{|x| x.start_with? "#{keyword} "}
|
40
|
-
end
|
41
|
-
|
42
|
-
return modules.flatten!
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
# somg;e-level inclusion
|
47
|
-
def include_content_from(file_path)
|
48
|
-
content = []
|
49
|
-
content << "\n# >>> #{file_path}"
|
50
|
-
content << file_path.readlines.map{|x| x.chomp} # TODO: support recursion??
|
51
|
-
content << "# <<< #{file_path}\n"
|
52
|
-
|
53
|
-
return content.flatten
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
# look for first occurace of mainfile
|
58
|
-
def just_find_it(here=Pathname.pwd)
|
59
|
-
mainfile = here + MAINFILE
|
60
|
-
return mainfile if mainfile.exist?
|
61
|
-
return nil if here == here.parent
|
62
|
-
return just_find_it(here.parent)
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
# use an external shell to expand system environment variables
|
67
|
-
def expand_file_path(a_path_string)
|
68
|
-
if a_path_string.start_with? '~'
|
69
|
-
a_path_string = "${HOME}" + a_path_string[1, a_path_string.size-1]
|
70
|
-
end
|
71
|
-
|
72
|
-
a_path_string = `echo "#{a_path_string}"`.chomp
|
73
|
-
|
74
|
-
return a_path_string
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
######################################################
|
79
|
-
# Main
|
80
|
-
|
81
|
-
mainfile = just_find_it
|
82
|
-
|
83
|
-
exit(0) if mainfile.nil?
|
84
|
-
|
85
|
-
basefile = mainfile.parent + BASEFILE
|
86
|
-
|
87
|
-
text = mainfile.readlines.map{|x| x.chomp} # drop the line ending from each line
|
88
|
-
|
89
|
-
modules = find_modules text
|
90
|
-
|
91
|
-
if modules.empty?
|
92
|
-
basefile.write text
|
93
|
-
exit(0)
|
94
|
-
end
|
95
|
-
|
96
|
-
modules.each do |a_line|
|
97
|
-
an_index = text.index a_line
|
98
|
-
begin_filename = a_line.index(' ')
|
99
|
-
module_filename = a_line[begin_filename, a_line.size - begin_filename].strip
|
100
|
-
|
101
|
-
if module_filename.empty?
|
102
|
-
STDERR.puts "#{an_index}: #{a_line}"
|
103
|
-
STDERR.puts "ERROR: No path/to/file was provided"
|
104
|
-
next
|
105
|
-
end
|
106
|
-
|
107
|
-
if module_filename.include?('~') || module_filename.include?('$')
|
108
|
-
module_filename = expand_file_path(module_filename)
|
109
|
-
end
|
110
|
-
|
111
|
-
module_path = Pathname.new(module_filename)
|
112
|
-
|
113
|
-
if module_path.relative?
|
114
|
-
module_path = mainfile.parent + module_path
|
115
|
-
end
|
116
|
-
|
117
|
-
if module_path.exist?
|
118
|
-
text[an_index] = include_content_from(module_path)
|
119
|
-
else
|
120
|
-
STDERR.puts "#{an_index}: #{a_line}"
|
121
|
-
STDERR.puts "| ERROR: File Does Not Exist - #{module_path}"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
basefile.write text.flatten!.join "\n"
|