grouik 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/src/bin/grouik +36 -0
- data/src/lib/grouik/cli.rb +172 -0
- data/src/lib/grouik/concerns/helpable.rb +19 -0
- data/src/lib/grouik/concerns.rb +16 -0
- data/src/lib/grouik/formatter.rb +67 -0
- data/src/lib/grouik/helpers/cli.rb +102 -0
- data/src/lib/grouik/helpers/loader.rb +72 -0
- data/src/lib/grouik/helpers/process.rb +82 -0
- data/src/lib/grouik/helpers.rb +50 -0
- data/src/lib/grouik/loadable.rb +51 -0
- data/src/lib/grouik/loader.rb +156 -0
- data/src/lib/grouik/output/message.rb +54 -0
- data/src/lib/grouik/output/messager.rb +86 -0
- data/src/lib/grouik/output.rb +13 -0
- data/src/lib/grouik/process.rb +195 -0
- data/src/lib/grouik/types.rb +46 -0
- data/src/lib/grouik/version_info.yml +16 -0
- data/src/lib/grouik.rb +101 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 83f25d1bc75415d52ac220b352808fc496eedbf1
|
4
|
+
data.tar.gz: 8315a3d896b9556d0b716a27855c8d2fd87c0ab8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b775cb7d82ec784f43d903ad6a36a98daa7de4db8ff343a83833cda9baff530c72d2a73639e51dd95dafa864f40e0033d603da89b10566ac60e1a95df7a60b2c
|
7
|
+
data.tar.gz: cc9ceee6b5db5d7c98083ccfe7fb954f61f70a73a4a81d1e706402c9a9caa44ec5df9d3b5d4f292c84e5a821d7e16c6840d8f4a55e789ed5acc9dcb16d6b03fe
|
data/src/bin/grouik
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
5
|
+
# License GPLv3+: GNU GPL version 3 or later
|
6
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
7
|
+
# This is free software: you are free to change and redistribute it.
|
8
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
9
|
+
|
10
|
+
require 'pathname'
|
11
|
+
$0 = Pathname.new(__FILE__).basename.to_s
|
12
|
+
|
13
|
+
# run bundled in a development context -------------------------------
|
14
|
+
if Pathname.new(__dir__).join('..', '..', '%s.gemspec' % $PROGRAM_NAME).file?
|
15
|
+
require 'rubygems'
|
16
|
+
require 'bundler'
|
17
|
+
Bundler.setup(:default)
|
18
|
+
end
|
19
|
+
|
20
|
+
# require lib requirements -------------------------------------------
|
21
|
+
[nil, :cli].each do |r|
|
22
|
+
req = r ? "#{$PROGRAM_NAME}/#{r}" : $PROGRAM_NAME
|
23
|
+
begin
|
24
|
+
require Pathname.new(__dir__).join('..', 'lib', '%s' % req)
|
25
|
+
rescue LoadError
|
26
|
+
begin
|
27
|
+
require req
|
28
|
+
rescue LoadError
|
29
|
+
require 'rubygems'
|
30
|
+
require req
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# process command line options and run -------------------------------
|
36
|
+
exit Grouik::Cli.run
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
require 'ostruct'
|
11
|
+
require 'pathname'
|
12
|
+
require 'yaml'
|
13
|
+
|
14
|
+
require 'grouik' unless defined?(Grouik)
|
15
|
+
require 'grouik/concerns'
|
16
|
+
|
17
|
+
# Grouik command line interface
|
18
|
+
#
|
19
|
+
# Provides a ready to use program, based on ``Grouik`` library
|
20
|
+
class Grouik::Cli
|
21
|
+
attr_reader :argv
|
22
|
+
attr_reader :options
|
23
|
+
attr_reader :arguments
|
24
|
+
|
25
|
+
include Grouik::Concerns::Helpable
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# Program name
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def program_name
|
32
|
+
Pathname.new($PROGRAM_NAME).basename('.rb').to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
# Run
|
36
|
+
#
|
37
|
+
# @param [Array] argv
|
38
|
+
def run(argv = ARGV)
|
39
|
+
self.new(argv).run
|
40
|
+
end
|
41
|
+
|
42
|
+
# default options
|
43
|
+
def defaults
|
44
|
+
{
|
45
|
+
stats: true,
|
46
|
+
paths: ['.'],
|
47
|
+
basedir: '.',
|
48
|
+
output: STDOUT,
|
49
|
+
ignores: [],
|
50
|
+
require: nil,
|
51
|
+
template: nil,
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [String]
|
57
|
+
def program_name
|
58
|
+
self.class.program_name
|
59
|
+
end
|
60
|
+
|
61
|
+
# Constructor
|
62
|
+
#
|
63
|
+
# @param [Array] argv
|
64
|
+
def initialize(argv = ARGV)
|
65
|
+
@argv = argv.clone
|
66
|
+
@options = self.class.defaults
|
67
|
+
# @options = config unless config.empty?
|
68
|
+
@arguments = []
|
69
|
+
end
|
70
|
+
|
71
|
+
# Provide an ``OptionParser``
|
72
|
+
#
|
73
|
+
# @return [OptionParser]
|
74
|
+
def parser
|
75
|
+
parser = helpers.get(:cli).make_parser(@options)
|
76
|
+
parser.banner = 'Usage: %s [OPTION]... [FILE]...' % program_name
|
77
|
+
|
78
|
+
parser
|
79
|
+
end
|
80
|
+
|
81
|
+
# Parse command line options
|
82
|
+
#
|
83
|
+
# Abort process (error code SHOULD BE ``22``) on invalid option
|
84
|
+
#
|
85
|
+
# @return [self]
|
86
|
+
def parse!
|
87
|
+
argv = self.argv.clone
|
88
|
+
begin
|
89
|
+
parser.parse!(argv)
|
90
|
+
rescue OptionParser::InvalidOption
|
91
|
+
STDERR.puts(parser)
|
92
|
+
exit(Errno::EINVAL::Errno)
|
93
|
+
end
|
94
|
+
@arguments = argv
|
95
|
+
# @options = prepare_options(@options)
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get processable items (based on command arguments), used during execution
|
100
|
+
#
|
101
|
+
# @return [Array<OpenStruct>]
|
102
|
+
def processables
|
103
|
+
processables = []
|
104
|
+
if arguments.empty?
|
105
|
+
processables[0] = OpenStruct.new(
|
106
|
+
path: Pathname.new(Dir.pwd),
|
107
|
+
options: options,
|
108
|
+
'file?' => false
|
109
|
+
)
|
110
|
+
else
|
111
|
+
arguments.each do |filepath|
|
112
|
+
config = helpers.get(:cli).read_config(filepath)
|
113
|
+
|
114
|
+
processables << OpenStruct.new(
|
115
|
+
path: Pathname.new(filepath).dirname,
|
116
|
+
file: Pathname.new(filepath),
|
117
|
+
options: config,
|
118
|
+
'file?' => true
|
119
|
+
)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
processables.map(&:freeze)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Execute CLI and return exit code
|
127
|
+
#
|
128
|
+
# @return [Fixnum]
|
129
|
+
def run
|
130
|
+
parse!
|
131
|
+
|
132
|
+
if options[:version]
|
133
|
+
STDOUT.puts helpers.get(:cli).version_chapter
|
134
|
+
return 0
|
135
|
+
end
|
136
|
+
|
137
|
+
processables.each do |processable|
|
138
|
+
Dir.chdir(processable.path) do
|
139
|
+
process(processable.options)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
0
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
|
147
|
+
# Initiate and run a new ``Process`` from options
|
148
|
+
#
|
149
|
+
# @param [Hash] options
|
150
|
+
# @return [Grouik::Process]
|
151
|
+
def process(options)
|
152
|
+
options = helpers.get(:cli).prepare_options(options)
|
153
|
+
|
154
|
+
process = Grouik.process do |process|
|
155
|
+
process.basedir = options.fetch(:basedir)
|
156
|
+
process.paths = options.fetch(:paths)
|
157
|
+
process.ignores = options[:ignores]
|
158
|
+
process.output = options.fetch(:output)
|
159
|
+
process.template = options[:template]
|
160
|
+
process.bootstrap = options[:require]
|
161
|
+
end
|
162
|
+
|
163
|
+
process.on_success do |process|
|
164
|
+
process.display_status if options[:stats]
|
165
|
+
end.on_failure do |process|
|
166
|
+
process.display_status if options[:stats]
|
167
|
+
exit Errno::ECANCELED::Errno
|
168
|
+
end
|
169
|
+
|
170
|
+
process
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
# Provide ``helpers`` method
|
10
|
+
module Grouik::Concerns::Helpable
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
# Loads helper
|
14
|
+
#
|
15
|
+
# @return [Grouik::Helpers]
|
16
|
+
def helpers
|
17
|
+
Grouik.get(:helpers)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
# Concerns in use
|
10
|
+
module Grouik::Concerns
|
11
|
+
require 'active_support/concern'
|
12
|
+
|
13
|
+
[:helpable].each do |concern|
|
14
|
+
require 'grouik/concerns/%s' % concern
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
require 'tenjin'
|
11
|
+
|
12
|
+
# Formatter used to render loadables
|
13
|
+
class Grouik::Formatter
|
14
|
+
attr_reader :options
|
15
|
+
attr_reader :loadables
|
16
|
+
attr_reader :template
|
17
|
+
|
18
|
+
def initialize(loadables, options = {})
|
19
|
+
@loadables = loadables
|
20
|
+
@options = options
|
21
|
+
@formatted = nil
|
22
|
+
@engine = Tenjin::Engine.new(cache: false)
|
23
|
+
@template = options[:template]
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Pathname|nil]
|
27
|
+
def template
|
28
|
+
@template ? Pathname.new(@template).realpath : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
formatted
|
33
|
+
end
|
34
|
+
|
35
|
+
def format
|
36
|
+
@formatted = @formatted.nil? ? output : @formatted
|
37
|
+
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
def formatted
|
42
|
+
format
|
43
|
+
@formatted.clone
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def format(loadables, options = {})
|
48
|
+
self.new(loadables, options).format
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def output
|
55
|
+
items = loadables.to_a.map { |i| "require '#{i}'" }
|
56
|
+
|
57
|
+
return items.join("\n") + "\n" unless template
|
58
|
+
|
59
|
+
context = {
|
60
|
+
requirement: lambda do |indent = nil|
|
61
|
+
items.map { |i| '%s%s' % [indent, i] }.join("\n")
|
62
|
+
end
|
63
|
+
}
|
64
|
+
|
65
|
+
@engine.render(template.to_s, context)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
# Cli helper, see ``Grouik::Cli``
|
12
|
+
class Grouik::Helpers::Cli
|
13
|
+
# Provide an ``OptionParser``
|
14
|
+
#
|
15
|
+
# @param [Hash] options
|
16
|
+
# @return [OptionParser]
|
17
|
+
def make_parser(options = {})
|
18
|
+
parser = OptionParser.new
|
19
|
+
|
20
|
+
{
|
21
|
+
basedir: ['--basedir=BASEDIR', 'Basedir [%s]' % options[:basedir]],
|
22
|
+
output: ['-o=OUTPUT', '--output=OUTPUT', 'Output [/dev/stdout]'],
|
23
|
+
require: ['-r=REQUIRE', '--require=REQUIRE',
|
24
|
+
'Required file on startup'],
|
25
|
+
ignores: ['--ignores x,y,z', Array, 'Ignores'],
|
26
|
+
paths: ['--paths x,y,z', Array, 'Paths'],
|
27
|
+
stats: ['--[no-]stats', 'Display some stats'],
|
28
|
+
version: ['--version', 'Display the version and exit']
|
29
|
+
}.each do |k, v|
|
30
|
+
parser.on(*v) { |o| options[k] = o }
|
31
|
+
end
|
32
|
+
|
33
|
+
parser
|
34
|
+
end
|
35
|
+
|
36
|
+
# Prepare options
|
37
|
+
#
|
38
|
+
# Process values in order to easify their use
|
39
|
+
#
|
40
|
+
# @param [Hash] options
|
41
|
+
# @return [Hash]
|
42
|
+
def prepare_options(options)
|
43
|
+
[:require, :output].each do |k|
|
44
|
+
next unless options[k]
|
45
|
+
begin
|
46
|
+
options[k] = Pathname.new(options[k])
|
47
|
+
rescue TypeError
|
48
|
+
next
|
49
|
+
end
|
50
|
+
unless options[k].absolute?
|
51
|
+
options[k] = Pathname.new(Dir.pwd).join(options[k])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
[:ignores, :paths].each do |k|
|
56
|
+
next unless options[k]
|
57
|
+
options[k] = [options[k]] if options[k].is_a? String
|
58
|
+
|
59
|
+
options[k] = options[k].to_a.map { |s| /#{s}/ } if :ignores == k
|
60
|
+
end
|
61
|
+
|
62
|
+
options
|
63
|
+
end
|
64
|
+
|
65
|
+
# Get the license
|
66
|
+
#
|
67
|
+
# @return [String]
|
68
|
+
def license
|
69
|
+
Grouik.version_info[:license].to_s.gsub(/\n{3}/mi, "\n\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get a displayable version
|
73
|
+
#
|
74
|
+
# Some inspiration taken from ``wget --version``
|
75
|
+
#
|
76
|
+
# @return [String]
|
77
|
+
def version_chapter
|
78
|
+
['%s %s on %s' % [Grouik.name, Grouik::VERSION, host_os],
|
79
|
+
nil,
|
80
|
+
license].join("\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [String]
|
84
|
+
def host_os
|
85
|
+
RbConfig::CONFIG['host_os']
|
86
|
+
end
|
87
|
+
|
88
|
+
# Read a config file
|
89
|
+
#
|
90
|
+
# @param [String] path
|
91
|
+
# @return [Hash]
|
92
|
+
def read_config(path)
|
93
|
+
file = Pathname.new(path.to_s)
|
94
|
+
config = YAML.safe_load(file.read)
|
95
|
+
|
96
|
+
h = config.each_with_object({}) do |(k, v), n|
|
97
|
+
n[k.intern] = v
|
98
|
+
end
|
99
|
+
|
100
|
+
h
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require 'grouik/types'
|
10
|
+
|
11
|
+
# Loader helper, see ``Grouik::Loader``
|
12
|
+
class Grouik::Helpers::Loader
|
13
|
+
# Make loadables
|
14
|
+
#
|
15
|
+
# @@return [Grouik::Types::Loadables]
|
16
|
+
def make_loadables
|
17
|
+
Grouik::Types::Loadables.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Make ignores
|
21
|
+
#
|
22
|
+
# @param [Array<String|Regexp>] input
|
23
|
+
# @return [Array<Regexp>]
|
24
|
+
def make_ignores(input)
|
25
|
+
input.to_a.map { |s| s.is_a?(Regexp) ? s : /^#{s}$/ }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Register paths
|
29
|
+
#
|
30
|
+
# @param [String] basedir
|
31
|
+
# @param [Array<String|Pathname>] paths
|
32
|
+
def register_paths(basedir, paths)
|
33
|
+
basedir = Pathname.new(basedir)
|
34
|
+
|
35
|
+
paths.reverse.each do |path|
|
36
|
+
$LOAD_PATH.unshift basedir.realpath.join(path).to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Pathname]
|
41
|
+
def pwd
|
42
|
+
Pathname.new(Dir.pwd)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [String] path
|
46
|
+
# @return [Array<Pathname>]
|
47
|
+
def files_in_path(path)
|
48
|
+
loaddir = path.to_s
|
49
|
+
basereg = %r{^#{Regexp.quote(loaddir)}\/}
|
50
|
+
|
51
|
+
Dir.glob(path.join('**/*.rb'))
|
52
|
+
.sort
|
53
|
+
.map { |file| file.gsub(basereg, '') }
|
54
|
+
.map { |file| Pathname.new(file) }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Collect loadables by paths
|
58
|
+
#
|
59
|
+
# @param [Array<String>] paths
|
60
|
+
# @return [Grouik::Types::Loadables]
|
61
|
+
def collect_loadables(paths)
|
62
|
+
loadables = self.make_loadables
|
63
|
+
|
64
|
+
paths.each do |path|
|
65
|
+
self.files_in_path(path).each do |file|
|
66
|
+
loadables = loadables.add_file(file, path.to_s)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
loadables
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
# Helper providing outputs (mostly useful in a CLI/Rake context)
|
10
|
+
#
|
11
|
+
# Main methods are ``display_errors`` and ``display_status``
|
12
|
+
class Grouik::Helpers::Process
|
13
|
+
# Display loading errors
|
14
|
+
#
|
15
|
+
# @param [Grouik::Process] process
|
16
|
+
# @return [self]
|
17
|
+
def display_errors(process)
|
18
|
+
process.errors.each do |_k, struct|
|
19
|
+
Grouik.message do |m|
|
20
|
+
m.stream = STDERR
|
21
|
+
m.type = 'error'
|
22
|
+
m.content = ('%s:%s: %s' % [
|
23
|
+
struct.source,
|
24
|
+
struct.line,
|
25
|
+
struct.message,
|
26
|
+
])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Display (on ``STDERR``) loader related statistics
|
32
|
+
#
|
33
|
+
# @param [Grouik::Process] process
|
34
|
+
# @return [self]
|
35
|
+
def display_status(process)
|
36
|
+
message = '%s: %s files; %s iterations; %s errors (%.4f) [%s]'
|
37
|
+
loader = process.loader
|
38
|
+
|
39
|
+
Grouik.message do |m|
|
40
|
+
m.stream = STDERR
|
41
|
+
m.type = 'status_%s' % status(process)
|
42
|
+
m.content = (message %
|
43
|
+
[
|
44
|
+
status(process).to_s.capitalize,
|
45
|
+
loader.loadables.size,
|
46
|
+
loader.attempts,
|
47
|
+
loader.errors.size,
|
48
|
+
loader.stats ? loader.stats.real : 0,
|
49
|
+
format_filepath(process.output)
|
50
|
+
])
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
# Denote status from process
|
56
|
+
#
|
57
|
+
# @return [Symbol]
|
58
|
+
def status(process)
|
59
|
+
statuses = { true => :success, false => :failure }
|
60
|
+
|
61
|
+
statuses.fetch(process.success?)
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
# Format a filepath with a ``require`` format
|
67
|
+
#
|
68
|
+
# @param [Pathname|String|Object] filepath
|
69
|
+
def format_filepath(filepath)
|
70
|
+
filepath = filepath.to_s
|
71
|
+
|
72
|
+
$LOAD_PATH.each do |path|
|
73
|
+
regexp = %r{^#{Regexp.quote(path.to_s)}\/}
|
74
|
+
if regexp.match(filepath)
|
75
|
+
filepath.gsub!(regexp, '').gsub!(/\.rb$/, '')
|
76
|
+
break
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
filepath
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2017 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
require 'active_support/inflector'
|
11
|
+
|
12
|
+
# Helpers (loader)
|
13
|
+
#
|
14
|
+
# Provide easy access to helpers
|
15
|
+
module Grouik::Helpers
|
16
|
+
class << self
|
17
|
+
# Retrieve helper by name
|
18
|
+
#
|
19
|
+
# @param [String|Symbol] target
|
20
|
+
# @return [Object]
|
21
|
+
def get(target)
|
22
|
+
class_name = self.classify(target)
|
23
|
+
|
24
|
+
require load_dir.join(target.to_s) unless const_defined?(class_name)
|
25
|
+
|
26
|
+
inflector.constantize(class_name).new
|
27
|
+
end
|
28
|
+
|
29
|
+
# Directory where helpers stand
|
30
|
+
#
|
31
|
+
# @return [Pathname]
|
32
|
+
def load_dir
|
33
|
+
Pathname.new(__FILE__.gsub(/\.rb$/, ''))
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
# @return ActiveSupport::Inflector
|
39
|
+
def inflector
|
40
|
+
ActiveSupport::Inflector
|
41
|
+
end
|
42
|
+
|
43
|
+
# Transform string
|
44
|
+
#
|
45
|
+
# return [String]
|
46
|
+
def classify(target)
|
47
|
+
'%s::%s' % [name, inflector.classify(target.to_s.gsub('/', '::'))]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
# Describe a loable item (Ruby file)
|
4
|
+
class Grouik::Loadable
|
5
|
+
attr_reader :base
|
6
|
+
attr_reader :path
|
7
|
+
attr_reader :basedir
|
8
|
+
|
9
|
+
# @param [String] base
|
10
|
+
# @param [String] path
|
11
|
+
# @param [String] basedir
|
12
|
+
def initialize(base, path, basedir = '.')
|
13
|
+
@base = Pathname.new(base)
|
14
|
+
@path = path
|
15
|
+
@basedir = Pathname.new(basedir).realpath
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [Boolean] format format as loadable from ``$LOAD_PATH``
|
19
|
+
# @return [String]
|
20
|
+
def path(format = false)
|
21
|
+
path = @path.to_s
|
22
|
+
|
23
|
+
{
|
24
|
+
true => path,
|
25
|
+
false => basedir.join(base, path).to_s
|
26
|
+
}[(format and loadable?)].gsub(/\.rb$/, '')
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [String]
|
30
|
+
def to_s
|
31
|
+
path(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Boolean]
|
35
|
+
def load(from = nil)
|
36
|
+
path = from ? Pathname.new(from).join(self.path) : self.path
|
37
|
+
|
38
|
+
return require path
|
39
|
+
end
|
40
|
+
|
41
|
+
def loadable?
|
42
|
+
self.class.paths.include?(basedir.join(base).to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
# @return [Array<String>]
|
47
|
+
def paths
|
48
|
+
$LOAD_PATH.map(&:to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|