nrser-rash 0.2.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 +7 -0
- data/.gitignore +104 -0
- data/.gitmodules +4 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/.yardopts +7 -0
- data/Gemfile +10 -0
- data/README.md +4 -0
- data/Rakefile +6 -0
- data/bash/source-profile.sh +17 -0
- data/dev/bin/.gitkeep +0 -0
- data/dev/bin/console +33 -0
- data/dev/bin/rake +3 -0
- data/dev/bin/rash +16 -0
- data/dev/bin/rspec +3 -0
- data/dev/ref/autocomplete.rb +62 -0
- data/dev/scratch/apps.AppleScript +14 -0
- data/dev/scratch/blocks.rb +232 -0
- data/dev/scratch/decorating_methods.rb +18 -0
- data/dev/scratch/functions.sh +80 -0
- data/dev/scratch/if.sh +16 -0
- data/dev/scratch/inc.rb +3 -0
- data/dev/scratch/inheriting_env/main.rb +44 -0
- data/dev/scratch/inheriting_env/sub.rb +9 -0
- data/dev/scratch/load_main.rb +5 -0
- data/dev/scratch/load_module.rb +19 -0
- data/dev/scratch/lsregister-dump.txt +30165 -0
- data/dev/scratch/main.rb +4 -0
- data/dev/scratch/optparse.rb +43 -0
- data/dev/scratch/overridding-cd.sh +53 -0
- data/dev/scratch/path.sh +22 -0
- data/dev/scratch/pirating_methods.rb +62 -0
- data/dev/scratch/profile.sh +624 -0
- data/dev/scratch/return.sh +5 -0
- data/dev/scratch/source_rvm.sh +11 -0
- data/dev/scratch/stub-names/project/test +3 -0
- data/exe/rash +4 -0
- data/lib/nrser/rash/cli/call.rb +137 -0
- data/lib/nrser/rash/cli/help.rb +29 -0
- data/lib/nrser/rash/cli/list.rb +36 -0
- data/lib/nrser/rash/cli/run.rb +54 -0
- data/lib/nrser/rash/cli.rb +21 -0
- data/lib/nrser/rash/config.rb +172 -0
- data/lib/nrser/rash/core_ext/object.rb +55 -0
- data/lib/nrser/rash/formatters.rb +105 -0
- data/lib/nrser/rash/functions.rb +154 -0
- data/lib/nrser/rash/helpers.rb +53 -0
- data/lib/nrser/rash/testing.rb +305 -0
- data/lib/nrser/rash/util.rb +260 -0
- data/lib/nrser/rash/version.rb +17 -0
- data/lib/nrser/rash.rb +40 -0
- data/nrser-rash.gemspec +48 -0
- data/tmp/.gitkeep +0 -0
- metadata +248 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
# Call a Rash function.
|
17
|
+
#
|
18
|
+
# @param [String] name
|
19
|
+
# Name of the function.
|
20
|
+
#
|
21
|
+
# @param [Array<String>] argv
|
22
|
+
# The shell arguments.
|
23
|
+
#
|
24
|
+
def self.call name, argv
|
25
|
+
|
26
|
+
logger.trace "calling #{ name.inspect }, argv: #{ argv.inspect }"
|
27
|
+
# look for options
|
28
|
+
options = {}
|
29
|
+
args = argv.reject do |arg|
|
30
|
+
# long options of form '--<name>=<value>'
|
31
|
+
if m = arg.match(/\A--([^=]*)(=?)(.*)/)
|
32
|
+
options[m[1].to_sym] = if m[2] == ''
|
33
|
+
true
|
34
|
+
else
|
35
|
+
m[3]
|
36
|
+
end
|
37
|
+
true
|
38
|
+
# short options of form '-<char>'
|
39
|
+
elsif arg.start_with? '-'
|
40
|
+
arg[1..-1].each_char do |char|
|
41
|
+
options[char] = true
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
logger.debug "options: #{ options.inspect }"
|
47
|
+
# options are the last arg, unless we didn't find any
|
48
|
+
#
|
49
|
+
# NOTE: this causes functions without an optional `options` arg
|
50
|
+
# on the end to raise an exception when called with any options.
|
51
|
+
#
|
52
|
+
# i think this is the correct behavior: the function can't handle
|
53
|
+
# options, and should error out.
|
54
|
+
args << options unless options.empty?
|
55
|
+
|
56
|
+
NRSER::Rash.load_functions
|
57
|
+
if name.include? '.'
|
58
|
+
namespace, method_name = name.split '.'
|
59
|
+
namespace = namespace.split '::'
|
60
|
+
else
|
61
|
+
namespace = []
|
62
|
+
method_name = name
|
63
|
+
end
|
64
|
+
mod = NRSER::Rash::Functions
|
65
|
+
namespace.each do |submod_name|
|
66
|
+
mod = mod.const_get(submod_name.capitalize)
|
67
|
+
end
|
68
|
+
begin
|
69
|
+
rtn = mod.method(method_name).call *args
|
70
|
+
rescue Exception => error
|
71
|
+
if NRSER::Rash.config( 'PRINT_ERRORS' ).truthy?
|
72
|
+
if NRSER::Rash.config( 'STACKTRACE' ).truthy?
|
73
|
+
raise error
|
74
|
+
else
|
75
|
+
logger.fatal error
|
76
|
+
# this is the error code that ruby seems to exit with when you
|
77
|
+
# don't check the exception
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
logger.debug "return value: #{ rtn.inspect }"
|
83
|
+
if formatted = format(rtn)
|
84
|
+
puts formatted
|
85
|
+
end
|
86
|
+
exit 0
|
87
|
+
end
|
88
|
+
|
89
|
+
# formats an object to write to `$stdout`.
|
90
|
+
# returns `nil` if there's nothing to write (different than returning '',
|
91
|
+
# indicating the empty string should be written).
|
92
|
+
def self.format(obj)
|
93
|
+
# TODO: should formatter be overridable with a env var?
|
94
|
+
# formatter = begin config('FORMATTER'); rescue NameError => e; nil; end
|
95
|
+
# logger.debug "formatter: #{ formatter.inspect }"
|
96
|
+
if obj.rash_formatter
|
97
|
+
# there is some sort of formatting info
|
98
|
+
# even if the value is a string, we want to follow the instructions
|
99
|
+
# hell, maybe we want to write the string out as json or something :/
|
100
|
+
if obj.rash_formatter.respond_to? :call
|
101
|
+
# the value responds to `call`, so call it to get the value
|
102
|
+
# TODO: should we check that it returns a `String`?
|
103
|
+
obj.rash_formatter.call(obj)
|
104
|
+
# NOTE: `Object.singleton_methods` returns an array of strings in 1.8
|
105
|
+
# and an array of symbols in 1.9, so use strings to work in
|
106
|
+
# both.
|
107
|
+
elsif NRSER::Rash::Formatters.
|
108
|
+
singleton_methods.
|
109
|
+
map {|_| _.to_s }.
|
110
|
+
include? obj.rash_formatter.to_s
|
111
|
+
# it's a symbol that identifies on of the {NRSER::Rash::Formatters}
|
112
|
+
# class methods, so call that
|
113
|
+
NRSER::Rash::Formatters.send obj.rash_formatter, obj
|
114
|
+
else
|
115
|
+
# whatever, call the default
|
116
|
+
NRSER::Rash::Formatters.send config('DEFAULT_FORMATTER'), obj
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# there is no formatting info
|
120
|
+
if obj.is_a? String
|
121
|
+
# in the case that a method passed back a `String`, i think we should
|
122
|
+
# consider it formatted and just print it
|
123
|
+
obj
|
124
|
+
elsif obj.nil?
|
125
|
+
# the result is nil and there has been no attempt to format it in
|
126
|
+
# a specific way that some program might need to recongize or
|
127
|
+
# something. at this point, i'm going to say that the function
|
128
|
+
# took some successful action and doesn't have anyhting to say about
|
129
|
+
# it, which i think means we shouldn't print anything
|
130
|
+
else
|
131
|
+
# otherwise, send it to the default formatter
|
132
|
+
NRSER::Rash::Formatters.send config('DEFAULT_FORMATTER'), obj
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
def self.help
|
17
|
+
# TODO: woefully incomplete
|
18
|
+
puts <<~EOF
|
19
|
+
Usage: rash COMMAND [ARGS...]
|
20
|
+
|
21
|
+
Commands:
|
22
|
+
list List functions you can call.
|
23
|
+
call Call a method from NRSER::Rash::Functions.
|
24
|
+
test Run tests for a method from NRSER::Rash::Functions.
|
25
|
+
help This message.
|
26
|
+
EOF
|
27
|
+
end
|
28
|
+
|
29
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
|
21
|
+
# Declarations
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
|
25
|
+
# Definitions
|
26
|
+
# =======================================================================
|
27
|
+
|
28
|
+
module NRSER::Rash::CLI
|
29
|
+
|
30
|
+
# List the Rash functions available.
|
31
|
+
def self.list
|
32
|
+
NRSER::Rash.load_functions
|
33
|
+
puts NRSER::Rash.function_names
|
34
|
+
end
|
35
|
+
|
36
|
+
end # module NRSER::Rash
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
module NRSER::Rash::CLI
|
15
|
+
|
16
|
+
# start here.
|
17
|
+
#
|
18
|
+
# this is the entry point for the script when executed. it expects a
|
19
|
+
# command as the first argument and dispatches to the associated method.
|
20
|
+
def self.run
|
21
|
+
SemanticLogger.add_appender io: $stderr, formatter: {
|
22
|
+
color: {
|
23
|
+
ap: {multiline: true},
|
24
|
+
}
|
25
|
+
}
|
26
|
+
SemanticLogger.default_level = NRSER::Rash.config( 'LOG_LEVEL' ).to_sym
|
27
|
+
|
28
|
+
# the command is the first argument
|
29
|
+
# we won't need or want it after this, so delete it
|
30
|
+
command = ARGV.shift
|
31
|
+
# filter out the command line config options
|
32
|
+
NRSER::Rash.filter_and_set_config ARGV
|
33
|
+
case command
|
34
|
+
when 'call'
|
35
|
+
# we are being asked to call a function. the name of the function is
|
36
|
+
# the second argument (now at index 0 since we deleted the command)
|
37
|
+
# and the rest of the arguments are passed to the function
|
38
|
+
call ARGV[0], ARGV[1..-1]
|
39
|
+
when 'test'
|
40
|
+
NRSER::Rash._test_function ARGV.shift #, ARGV[1, ARGV.length]
|
41
|
+
when 'list'
|
42
|
+
list
|
43
|
+
when 'help', '-h', '--help', nil
|
44
|
+
help
|
45
|
+
# Exit with error so these calls don't work with `&&` in shell
|
46
|
+
exit 1
|
47
|
+
when '--version', 'version', '-v'
|
48
|
+
puts NRSER::Rash::VERSION
|
49
|
+
else
|
50
|
+
call command, ARGV
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end # module NRSER::Rash::CLI
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Definitions
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Where the CLI commands live as class methods.
|
8
|
+
#
|
9
|
+
module NRSER::Rash::CLI
|
10
|
+
|
11
|
+
include SemanticLogger::Loggable
|
12
|
+
|
13
|
+
end # module NRSER::Rash::CLI
|
14
|
+
|
15
|
+
|
16
|
+
# Post-Processing
|
17
|
+
# =======================================================================
|
18
|
+
require_relative './cli/call'
|
19
|
+
require_relative './cli/help'
|
20
|
+
require_relative './cli/list'
|
21
|
+
require_relative './cli/run'
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
using NRSER
|
21
|
+
using NRSER::Types
|
22
|
+
|
23
|
+
|
24
|
+
# Definitions
|
25
|
+
# =======================================================================
|
26
|
+
|
27
|
+
# @todo document NRSER::Rash module.
|
28
|
+
module NRSER::Rash
|
29
|
+
|
30
|
+
COMMAND_LINE_CONFIG = {}
|
31
|
+
|
32
|
+
|
33
|
+
# Get a config value by name. First looks for an env var defined with
|
34
|
+
# an added `'RASH_'` prefix, then for a const in the {NRSER::Rash}
|
35
|
+
# module with the provided name.
|
36
|
+
#
|
37
|
+
# @todo This example is out of date...
|
38
|
+
#
|
39
|
+
# Easiest to explain by example:
|
40
|
+
#
|
41
|
+
# NRSER::Rash::config('BLAH')
|
42
|
+
#
|
43
|
+
# will first see if there is an env var named
|
44
|
+
#
|
45
|
+
# 'RASH_BLAH'
|
46
|
+
#
|
47
|
+
# defined, and return it's value if so.
|
48
|
+
#
|
49
|
+
# Otherwise, it will try and return
|
50
|
+
#
|
51
|
+
# NRSER::RASH::Config::BLAH
|
52
|
+
#
|
53
|
+
# raising an exception if it's not found.
|
54
|
+
#
|
55
|
+
# Defined here so it can be used when defining the
|
56
|
+
# `NRSER::Rash::Config::<name>` consts.
|
57
|
+
#
|
58
|
+
def self.config name, *default
|
59
|
+
if default.length > 1
|
60
|
+
raise ArgumentError,
|
61
|
+
"wrong number of arguments" \
|
62
|
+
"(given #{ 1 + default.length }, expected 1-2)"
|
63
|
+
end
|
64
|
+
|
65
|
+
# command line config options take precedent (those that start with
|
66
|
+
# '--RASH_', which are never passed to the function)
|
67
|
+
if COMMAND_LINE_CONFIG.key? name
|
68
|
+
COMMAND_LINE_CONFIG[name]
|
69
|
+
elsif ENV.key? "RASH_#{ name }"
|
70
|
+
ENV["RASH_#{ name }"]
|
71
|
+
else
|
72
|
+
begin
|
73
|
+
Config.const_get(name)
|
74
|
+
rescue NameError => e
|
75
|
+
if default.empty?
|
76
|
+
raise
|
77
|
+
else
|
78
|
+
default[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# Where the default config options are set.
|
86
|
+
#
|
87
|
+
# These are overridden by:
|
88
|
+
#
|
89
|
+
# 1. By command line options of the form
|
90
|
+
#
|
91
|
+
# --RASH_<name>
|
92
|
+
#
|
93
|
+
# where `<name>` corresponds to the `NRSER::Rash::Config::<name>`
|
94
|
+
# constant.
|
95
|
+
#
|
96
|
+
# 2. By environment variables of the form
|
97
|
+
#
|
98
|
+
# RASH_<name>
|
99
|
+
#
|
100
|
+
# where `<name>` corresponds to the `NRSER::Rash::Config.<name>`
|
101
|
+
# constant.
|
102
|
+
#
|
103
|
+
# Don't access these directly, use {NRSER::Rash.config} to access in
|
104
|
+
# proper precedence.
|
105
|
+
#
|
106
|
+
module Config
|
107
|
+
# Where to look for Rash files
|
108
|
+
HOME = ENV['HOME']
|
109
|
+
|
110
|
+
# Where to look for the Rash profile file
|
111
|
+
PROFILE = "#{ NRSER::Rash.config('HOME') }/profile.rb"
|
112
|
+
|
113
|
+
# Where to look for the Rash functions file
|
114
|
+
FUNCTIONS = "#{ NRSER::Rash.config('HOME') }/functions.rb"
|
115
|
+
|
116
|
+
# The default {NRSER::Rash::Formatter} to use
|
117
|
+
DEFAULT_FORMATTER = 'pp'
|
118
|
+
|
119
|
+
# Logging level
|
120
|
+
LOG_LEVEL = :info
|
121
|
+
|
122
|
+
# Print stacktrace on top-level function error
|
123
|
+
STACKTRACE = 'false'
|
124
|
+
|
125
|
+
# Don't print errors
|
126
|
+
PRINT_ERRORS = 'true'
|
127
|
+
|
128
|
+
# Stub function namespace separator
|
129
|
+
STUB_NAMESPACE_SEPERATOR = '__'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Rash's project dir
|
133
|
+
ROOT_DIR = File.expand_path(File.dirname(__FILE__) + '/..')
|
134
|
+
|
135
|
+
# Executable
|
136
|
+
EXECUTABLE = ROOT_DIR + '/bin/rash'
|
137
|
+
|
138
|
+
# Proxy to {NRSER.truthy?}
|
139
|
+
#
|
140
|
+
def self.truthy? string
|
141
|
+
NRSER.truthy? string
|
142
|
+
end
|
143
|
+
|
144
|
+
# Old name without `?`
|
145
|
+
singleton_class.send :alias_method, :truthy, :truthy?
|
146
|
+
|
147
|
+
|
148
|
+
# Proxy to {NRSER.falsy?}
|
149
|
+
#
|
150
|
+
def self.falsy? string
|
151
|
+
return string.falsy?
|
152
|
+
end
|
153
|
+
|
154
|
+
# Old name
|
155
|
+
singleton_class.send :alias_method, :falsey, :falsy?
|
156
|
+
|
157
|
+
|
158
|
+
def self.filter_and_set_config(args)
|
159
|
+
args.reject! do |arg|
|
160
|
+
# long options of form '--<name>=<value>'
|
161
|
+
if m = arg.match(/\A--RASH_([^=]*)(=?)(.*)/)
|
162
|
+
COMMAND_LINE_CONFIG[m[1]] = if m[2] == ''
|
163
|
+
true
|
164
|
+
else
|
165
|
+
m[3]
|
166
|
+
end
|
167
|
+
true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end # module NRSER::Rash
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Object
|
2
|
+
# Monkey-patch to add an instance variable named `rash_formatter`
|
3
|
+
# to `Object` to control how that object is formatted for printing if
|
4
|
+
# it's the final value returned to {NRSER::Rash::CLI.call}.
|
5
|
+
#
|
6
|
+
# The value should either be a symbol identifying a method on
|
7
|
+
# {NRSER::Rash::Formatters} to call or a callable that takes the object
|
8
|
+
# as it's only argument and returns a formatted `String`.
|
9
|
+
#
|
10
|
+
attr_accessor :rash_formatter
|
11
|
+
|
12
|
+
# shortcut method to set the `rash_formatter` and return the object.
|
13
|
+
# this method is hacked up a bit to support the following syntax:
|
14
|
+
#
|
15
|
+
# {:x => 1, :y => 2}.rash_formatter_tap :json
|
16
|
+
#
|
17
|
+
# {:x => 1, :y => 2}.rash_formatter_tap do |obj|
|
18
|
+
# "here's the object: #{ obj.inspect }"
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# which returns the object itself, allowing it to easily be tacked on to
|
22
|
+
# the last statement in a method. it's equivalent to:
|
23
|
+
#
|
24
|
+
# {:x => 1, :y => 2}.tap {|obj| obj.rash_formatter = :json}
|
25
|
+
#
|
26
|
+
# {:x => 1, :y => 2}.tap do |obj|
|
27
|
+
# obj.rash_formatter = Proc.new do |obj|
|
28
|
+
# "here's the object: #{ obj.inpsect }"
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def rash_formatter_tap(formatter = (default = true; nil), &block)
|
33
|
+
if default
|
34
|
+
if block.nil?
|
35
|
+
# neither the `formatter` arg or a block were supplied, so
|
36
|
+
# the method is acting as an attribute reader, return the
|
37
|
+
# value
|
38
|
+
raise ArgumentError.new "must provide an argument or block."
|
39
|
+
else
|
40
|
+
# only a block was supplied, set it as the formatter and
|
41
|
+
# return the object
|
42
|
+
@rash_formatter = block
|
43
|
+
self
|
44
|
+
end
|
45
|
+
else
|
46
|
+
if block
|
47
|
+
raise ArgumentError.new "can't provide an argument and block."
|
48
|
+
else
|
49
|
+
# only `formatter` arg was supplied, set it and return the object
|
50
|
+
@rash_formatter = formatter
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end # class Object
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
using NRSER
|
8
|
+
using NRSER::Types
|
9
|
+
|
10
|
+
|
11
|
+
# Definitions
|
12
|
+
# =======================================================================
|
13
|
+
|
14
|
+
# these are functions mapping an `Object` to a `String` for printing.
|
15
|
+
# their names can be used as values for `Object.rash_formatter` to indicate
|
16
|
+
# Rash should use that function to print the object.
|
17
|
+
#
|
18
|
+
module NRSER::Rash::Formatters
|
19
|
+
def self.yaml(obj)
|
20
|
+
require 'yaml'
|
21
|
+
YAML.dump(obj)
|
22
|
+
end
|
23
|
+
|
24
|
+
# print a white-space formatted key/value table given a hash.
|
25
|
+
# keys and values are printed cast to strings, and nested
|
26
|
+
# hashes are treated as sub-keys:
|
27
|
+
#
|
28
|
+
# NRSER::Rash::Formatters.kv({
|
29
|
+
# :scheme => "https",
|
30
|
+
# :host => "www.google.com",
|
31
|
+
# :port => 443,
|
32
|
+
# :params => {
|
33
|
+
# :q => "blah",
|
34
|
+
# :oq => "blah",
|
35
|
+
# :aqs => "chrome.0.57j60l4j59.468",
|
36
|
+
# :sourceid => "chrome",
|
37
|
+
# :ie => "UTF-8"
|
38
|
+
# },
|
39
|
+
# :fragment => nil
|
40
|
+
# })
|
41
|
+
#
|
42
|
+
# scheme: https
|
43
|
+
# host: www.google.com
|
44
|
+
# port: 443
|
45
|
+
# params:
|
46
|
+
# q: blah
|
47
|
+
# oq: blah
|
48
|
+
# aqs: chrome.0.57j60l4j59.468
|
49
|
+
# sourceid: chrome
|
50
|
+
# ie: UTF-8
|
51
|
+
# fragment:
|
52
|
+
#
|
53
|
+
def self.kv(hash)
|
54
|
+
find_width = lambda do |hash, indent|
|
55
|
+
width = 0
|
56
|
+
hash.each do |key, value|
|
57
|
+
this_width = if value.is_a? Hash
|
58
|
+
find_width.call(value, indent + 2)
|
59
|
+
else
|
60
|
+
key.to_s.length + indent
|
61
|
+
end
|
62
|
+
if this_width > width
|
63
|
+
width = this_width
|
64
|
+
end
|
65
|
+
end
|
66
|
+
width
|
67
|
+
end
|
68
|
+
width = find_width.call(hash, 0)
|
69
|
+
out = ''
|
70
|
+
write_out = lambda do |hash, indent|
|
71
|
+
hash.each do |key, value|
|
72
|
+
out << ' ' * indent \
|
73
|
+
<< "#{ key }: " \
|
74
|
+
<< ' ' * (width - key.to_s.length - indent)
|
75
|
+
if value.is_a? Hash
|
76
|
+
out << "\n"
|
77
|
+
write_out.call(value, indent + 2)
|
78
|
+
else
|
79
|
+
out << "#{ value }\n"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
write_out.call(hash, 0)
|
84
|
+
out
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.json(obj)
|
88
|
+
require 'json'
|
89
|
+
JSON.dump(obj)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.json_pp(obj)
|
93
|
+
require 'json'
|
94
|
+
JSON.pretty_generate(obj)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.pp(obj)
|
98
|
+
require 'pp'
|
99
|
+
require 'stringio'
|
100
|
+
sio = StringIO.new
|
101
|
+
PP.pp(obj, sio)
|
102
|
+
sio.string
|
103
|
+
end
|
104
|
+
|
105
|
+
end # module NRSER::Rash::Formatters
|