lucie-lib 0.0.19 → 0.0.20
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/lib/lucie/app.rb +49 -5
- data/lib/lucie/command_line_parser.rb +106 -65
- data/lib/lucie/command_line_slicer.rb +72 -59
- data/lib/lucie/controller/base.rb +1 -1
- data/lib/lucie/exceptions.rb +18 -17
- data/lib/lucie/validators/base.rb +7 -0
- data/lib/lucie/validators/mandatory_option.rb +3 -0
- data/lib/lucie/version.rb +1 -1
- data/lib/lucie.rb +32 -0
- data/test/unit/command_line_parser_test.rb +2 -0
- data/test/unit/command_line_slicer_test.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87f0e44f7eec657401b9a2c77468dc9c61f216c2
|
4
|
+
data.tar.gz: 97b29ace94517aeff18c3398c93dc8f4659dff4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aaaa30a83a84dce02f4025757df1d3f680a9496750fdd5d3343a8c75366c40bee0d8ec537db3361ad32b0339eec9554d300547088482f56f1e06f9536cc9ba46
|
7
|
+
data.tar.gz: 0f6700a31e0a14f325c12a6ad73b6cc43407c9204060ced25b199f98e909a37e16528d35b6c69d75601f39f6039816f062352acfae28efa661dc62d7e59bdb28
|
data/lib/lucie/app.rb
CHANGED
@@ -1,34 +1,75 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
module Lucie
|
4
|
-
|
5
|
-
#
|
2
|
+
|
3
|
+
#
|
4
|
+
# Lucie::App represents the application context. When a lucie application starts,
|
5
|
+
# it requires information about its environment, like root path, env, command. App
|
6
|
+
# also responsible for loading the right controller and to execute the process how the
|
7
|
+
# input will be parsed and the business logic is executed.
|
6
8
|
#
|
7
9
|
class App
|
8
10
|
|
9
11
|
class << self
|
12
|
+
#
|
13
|
+
# Let the exception leave the application when any occur.
|
14
|
+
#
|
15
|
+
# Normally the application doesn't raise any exception, just stops quietly.
|
16
|
+
# When the application is under debugging, developer needs more, detailed description
|
17
|
+
# about the problem. Suggested to turn this attribute on during developing.
|
18
|
+
#
|
19
|
+
# App.raise_exception = true
|
20
|
+
#
|
10
21
|
attr_accessor :raise_exception
|
22
|
+
|
23
|
+
# Sets the log level of the application.
|
24
|
+
#
|
11
25
|
attr_accessor :log_level
|
26
|
+
|
27
|
+
#
|
28
|
+
# Root directory of the source of application.
|
29
|
+
#
|
30
|
+
# Template and other source paths are calculated relatively to this directory.
|
31
|
+
#
|
12
32
|
attr_accessor :root
|
33
|
+
|
13
34
|
@raise_exception = false
|
14
35
|
@log_level = :info
|
15
36
|
end
|
16
37
|
|
38
|
+
# Command line input that is being executed. Usually it equals with ARGV.
|
39
|
+
#
|
17
40
|
attr_reader :command
|
41
|
+
|
42
|
+
# Root of the application. Same as App.root, it's a reference for that.
|
43
|
+
#
|
18
44
|
attr_reader :root
|
45
|
+
|
46
|
+
# The directory where from the application has been executed.
|
47
|
+
#
|
19
48
|
attr_reader :pwd
|
20
49
|
|
50
|
+
# Initializes and starts the applicaiton. Shortcut for self.init && self.start
|
51
|
+
#
|
21
52
|
def self.run(command = ARGV, root = nil, pwd = nil)
|
22
53
|
root ||= File.expand_path("..", File.dirname(Kernel.caller[0]))
|
23
54
|
instance = self.init(command, root, pwd)
|
24
55
|
self.start(instance)
|
25
56
|
end
|
26
57
|
|
58
|
+
# Initializes the application.
|
59
|
+
#
|
60
|
+
# @param command [Array or String]
|
61
|
+
# @param root [String] Path of the root of the app. [default: current application's path]
|
62
|
+
# @param pwd [String] Path of the terminal position.
|
63
|
+
#
|
27
64
|
def self.init(command = ARGV, root = nil, pwd = nil)
|
28
65
|
root ||= File.expand_path("..", File.dirname(Kernel.caller[0]))
|
29
66
|
self.new(command, root, pwd)
|
30
67
|
end
|
31
68
|
|
69
|
+
# Starts the application instance and returns its exit status.
|
70
|
+
#
|
71
|
+
# @param instance [App] Application instance
|
72
|
+
#
|
32
73
|
def self.start(instance)
|
33
74
|
instance.start
|
34
75
|
instance.exit_value
|
@@ -36,21 +77,24 @@ module Lucie
|
|
36
77
|
|
37
78
|
def initialize(command, root, pwd = nil)
|
38
79
|
@root = root
|
39
|
-
@command = CommandLineParser.new(command)
|
80
|
+
@command = Core::CommandLineParser.new(command)
|
40
81
|
@exit_value ||= 0
|
41
82
|
@task = nil
|
42
83
|
@pwd = pwd || ENV["PWD"]
|
43
84
|
Dir.chdir(@pwd)
|
44
85
|
end
|
45
86
|
|
87
|
+
# Starts the application.
|
46
88
|
def start
|
47
89
|
help? ? call_help : call_method_invoking_process
|
48
90
|
end
|
49
91
|
|
92
|
+
# Exit status of the application
|
50
93
|
def exit_value
|
51
94
|
@exit_value
|
52
95
|
end
|
53
96
|
|
97
|
+
# Environment of the application. Contains the ENV of the terminal.
|
54
98
|
def env
|
55
99
|
ENV
|
56
100
|
end
|
@@ -1,87 +1,128 @@
|
|
1
1
|
require "lucie/command_line_slicer"
|
2
2
|
|
3
|
-
|
3
|
+
module Lucie
|
4
4
|
|
5
|
-
|
5
|
+
module Core
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@latest_option = nil
|
7
|
+
# Command line parser extracts the controller name and action from the
|
8
|
+
# application input and prepares the params hash for the controller.
|
9
|
+
#
|
10
|
+
class CommandLineParser
|
12
11
|
|
13
|
-
|
14
|
-
end
|
12
|
+
attr_reader :options
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
# Initializes a CommandLineParser
|
15
|
+
#
|
16
|
+
# @param parameters [String|Array] Input that needs to be processed
|
17
|
+
#
|
18
|
+
def initialize(parameters)
|
19
|
+
@params_str = parameters.class == Array ? parameters.join(" ") : parameters
|
20
|
+
@options = {}
|
21
|
+
@options[:args] = []
|
22
|
+
@latest_option = nil
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
24
|
+
parse_options()
|
25
|
+
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
# Gets the value of an option
|
28
|
+
#
|
29
|
+
# For "--option value" the self[:option] returns "value"
|
30
|
+
#
|
31
|
+
# @param name [Symbol] Name of the option
|
32
|
+
def [](name)
|
33
|
+
@options[name]
|
34
|
+
end
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
# Shift the parameter list. Useful for removing the controller's name
|
37
|
+
# from the beginning.
|
38
|
+
#
|
39
|
+
def shift
|
40
|
+
@options[:args].shift
|
41
|
+
end
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
# Pairs short and long options.
|
44
|
+
#
|
45
|
+
# When -o is a shortened version of --option, then params[:o] must return
|
46
|
+
# the same value as params[:option]. This method pairs these options.
|
47
|
+
#
|
48
|
+
# @param short [Symbol] Short version of the option
|
49
|
+
# @param long [Symbol] Long version of the option
|
50
|
+
#
|
51
|
+
def pair(short, long)
|
52
|
+
short_p = remove_dashes(short).to_sym
|
53
|
+
long_p = remove_dashes(long).to_sym
|
54
|
+
|
55
|
+
if @options[short_p].class == String
|
56
|
+
@options[long_p] = @options[short_p]
|
57
|
+
else
|
58
|
+
@options[short_p] = @options[long_p]
|
59
|
+
end
|
60
|
+
end
|
38
61
|
|
39
|
-
|
40
|
-
|
41
|
-
|
62
|
+
# Is the option defined?
|
63
|
+
#
|
64
|
+
# @param option [Symbol] Name of the option
|
65
|
+
def has_option?(option)
|
66
|
+
@options[remove_dashes(option).to_sym] || false
|
67
|
+
end
|
42
68
|
|
43
|
-
|
44
|
-
|
45
|
-
|
69
|
+
# Get the values which has no options.
|
70
|
+
#
|
71
|
+
# Arguments are values without any option or tag. When the option
|
72
|
+
# name is undefined, the value gets placed in args.
|
73
|
+
#
|
74
|
+
def args
|
75
|
+
@options[:args].dup
|
76
|
+
end
|
46
77
|
|
47
|
-
|
78
|
+
# Checks whether the value is in the args.
|
79
|
+
#
|
80
|
+
# @param option [String] Name of the argument.
|
81
|
+
#
|
82
|
+
def has_arg?(option)
|
83
|
+
@options[:args].include?(option)
|
84
|
+
end
|
48
85
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
86
|
+
private
|
87
|
+
|
88
|
+
def parse_options
|
89
|
+
array_of_options.each do |option|
|
90
|
+
if is_option?(option)
|
91
|
+
save_option(option)
|
92
|
+
else
|
93
|
+
save_parameter(option)
|
94
|
+
end
|
95
|
+
end
|
55
96
|
end
|
56
|
-
end
|
57
|
-
end
|
58
97
|
|
59
|
-
|
60
|
-
|
61
|
-
|
98
|
+
def is_option?(option)
|
99
|
+
option =~ /^-/
|
100
|
+
end
|
62
101
|
|
63
|
-
|
64
|
-
|
65
|
-
|
102
|
+
def remove_dashes(option)
|
103
|
+
option.gsub(/^-+/, "")
|
104
|
+
end
|
66
105
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
106
|
+
def save_option(option)
|
107
|
+
without_dashes = remove_dashes(option)
|
108
|
+
@options[without_dashes.to_sym] = true
|
109
|
+
@latest_option = without_dashes.to_sym
|
110
|
+
end
|
72
111
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
112
|
+
def save_parameter(option)
|
113
|
+
if @options[@latest_option].class == String
|
114
|
+
@options[@latest_option] += [" ", option].join
|
115
|
+
elsif !@latest_option
|
116
|
+
@options[:args] ||= []
|
117
|
+
@options[:args] << option
|
118
|
+
else
|
119
|
+
@options[@latest_option] = option
|
120
|
+
end
|
121
|
+
end
|
83
122
|
|
84
|
-
|
85
|
-
|
123
|
+
def array_of_options
|
124
|
+
Core::CommandLineSlicer.new(@params_str).to_a
|
125
|
+
end
|
126
|
+
end
|
86
127
|
end
|
87
128
|
end
|
@@ -1,77 +1,90 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
module Lucie
|
2
|
+
|
3
|
+
module Core
|
4
|
+
# Command Line Slicer can split the input string to words.
|
5
|
+
#
|
6
|
+
class CommandLineSlicer
|
7
|
+
|
8
|
+
# Initializes a CommandLineSlicer object with the input.
|
9
|
+
#
|
10
|
+
# @param line [String] The input that need to be sliced
|
11
|
+
def initialize(line)
|
12
|
+
@line = line.split("")
|
13
|
+
@parts = []
|
14
|
+
@neutral_status = false
|
15
|
+
@quotation_open = false
|
16
|
+
@scanned = ""
|
17
|
+
end
|
9
18
|
|
10
|
-
|
11
|
-
|
12
|
-
|
19
|
+
# Returns the words of the input in an array.
|
20
|
+
#
|
21
|
+
def to_a
|
22
|
+
each_char do |char|
|
23
|
+
if boundary? char
|
24
|
+
save_chunk
|
25
|
+
elsif in_quoatation? char
|
26
|
+
toggle_quotation_state
|
27
|
+
elsif neutral? char
|
28
|
+
neutral :on
|
29
|
+
else
|
30
|
+
neutral :off
|
31
|
+
append char
|
32
|
+
end
|
33
|
+
end
|
13
34
|
save_chunk
|
14
|
-
elsif in_quoatation? char
|
15
|
-
toggle_quotation_state
|
16
|
-
elsif neutral? char
|
17
|
-
neutral :on
|
18
|
-
else
|
19
|
-
neutral :off
|
20
|
-
append char
|
21
35
|
end
|
22
|
-
end
|
23
|
-
save_chunk
|
24
|
-
end
|
25
36
|
|
26
|
-
private
|
37
|
+
private
|
27
38
|
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
def append(char)
|
40
|
+
@scanned += char
|
41
|
+
end
|
31
42
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
43
|
+
def each_char(&blk)
|
44
|
+
while @line.size > 0
|
45
|
+
yield(@line.shift)
|
46
|
+
end
|
47
|
+
end
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
def toggle_quotation_state
|
50
|
+
@quotation_open = !@quotation_open
|
51
|
+
end
|
41
52
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
53
|
+
def save_chunk
|
54
|
+
@parts << @scanned if @scanned != ""
|
55
|
+
@scanned = ""
|
56
|
+
@parts
|
57
|
+
end
|
47
58
|
|
48
|
-
|
49
|
-
|
50
|
-
|
59
|
+
def neutral(sym)
|
60
|
+
@neutral_status = (sym == :on)
|
61
|
+
end
|
51
62
|
|
52
|
-
private
|
63
|
+
private
|
53
64
|
|
54
|
-
|
55
|
-
|
56
|
-
|
65
|
+
def neutral_chars
|
66
|
+
["\\"]
|
67
|
+
end
|
57
68
|
|
58
|
-
|
59
|
-
|
60
|
-
|
69
|
+
def boundary_chars
|
70
|
+
[" "]
|
71
|
+
end
|
61
72
|
|
62
|
-
|
63
|
-
|
64
|
-
|
73
|
+
def quotation_chars
|
74
|
+
["\"", "'"]
|
75
|
+
end
|
65
76
|
|
66
|
-
|
67
|
-
|
68
|
-
|
77
|
+
def boundary?(char)
|
78
|
+
boundary_chars.include?(char) && !@neutral_status && !@quotation_open
|
79
|
+
end
|
69
80
|
|
70
|
-
|
71
|
-
|
72
|
-
|
81
|
+
def in_quoatation?(char)
|
82
|
+
quotation_chars.include?(char) && !@neutral_status
|
83
|
+
end
|
73
84
|
|
74
|
-
|
75
|
-
|
85
|
+
def neutral?(char)
|
86
|
+
neutral_chars.include?(char) && !@neutral_status
|
87
|
+
end
|
88
|
+
end
|
76
89
|
end
|
77
90
|
end
|
data/lib/lucie/exceptions.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
module Lucie
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
module Exceptions
|
3
|
+
class RequestError < StandardError
|
4
|
+
def initialize(validator)
|
5
|
+
super "#{validator.description} (#{validator.short_option}) is mandatory parameter"
|
6
|
+
end
|
5
7
|
end
|
6
|
-
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
class ControllerNotFound < StandardError
|
10
|
+
def initialize(controller_name)
|
11
|
+
super "Controller is not found for #{controller_name}."
|
12
|
+
end
|
11
13
|
end
|
12
|
-
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
class ActionNotFound < StandardError
|
16
|
+
def initialize(action, controller)
|
17
|
+
super "#{action} is not found in #{controller}."
|
18
|
+
end
|
17
19
|
end
|
18
|
-
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
class ExitRequest < Exception
|
22
|
+
attr_reader :exit
|
23
|
+
def initialize(exit)
|
24
|
+
@exit = exit
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
|
-
|
27
28
|
end
|
data/lib/lucie/version.rb
CHANGED
data/lib/lucie.rb
CHANGED
@@ -1,10 +1,42 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
|
3
|
+
# Copyright (c) 2014 Laszlo Papp, <laszlo.papp@bteam.hu>
|
4
|
+
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
1
23
|
$LOAD_PATH << File.expand_path("..", __FILE__)
|
2
24
|
|
3
25
|
require "lucie/version"
|
4
26
|
require "lucie/exceptions"
|
5
27
|
|
28
|
+
|
29
|
+
# Lucie is a modular MVC terminal application framework. With Lucie easy to create
|
30
|
+
# command line application using controllers to describe the process, models to store
|
31
|
+
# additional data permanently, and views to generate configuration files for applications.
|
32
|
+
#
|
33
|
+
# Lucie-lib is a glue for these MVC components and provide additional helper methods to
|
34
|
+
# support faster and easier developing.
|
35
|
+
#
|
6
36
|
module Lucie
|
7
37
|
|
38
|
+
include ::Lucie::Exceptions
|
39
|
+
|
8
40
|
module Controller
|
9
41
|
autoload :ExitRequest, "lucie/controller/exit_request"
|
10
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lucie-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nucc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|