yay 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/yay/application.rb +24 -6
- data/lib/yay/colour_wheel.rb +71 -57
- data/lib/yay/colourizer.rb +22 -4
- data/lib/yay/errors.rb +76 -16
- data/lib/yay/installer.rb +126 -3
- data/lib/yay/lexer.rb +9 -4
- data/lib/yay/lexer_regex.rb +3 -0
- data/lib/yay/lister.rb +59 -0
- data/lib/yay/loader.rb +2 -0
- data/lib/yay/parser.rb +146 -121
- data/lib/yay/parser_gen.rb +20 -18
- data/lib/yay/paths.rb +9 -5
- data/lib/yay/rule_set.rb +3 -1
- data/lib/yay/version.rb +15 -12
- metadata +15 -14
data/lib/yay/application.rb
CHANGED
@@ -3,6 +3,8 @@ require 'yay/colourizer'
|
|
3
3
|
require 'yay/version'
|
4
4
|
|
5
5
|
class Yay
|
6
|
+
# this class acts as controller for yay. it interprets user input and
|
7
|
+
# coordinates with the parser
|
6
8
|
class Application
|
7
9
|
|
8
10
|
# arg that can be used if you don't want the application to do anything
|
@@ -14,11 +16,12 @@ class Yay
|
|
14
16
|
# arg that can be used to dump the version and exit
|
15
17
|
SHOW_VERSION_ARG = '--version'
|
16
18
|
|
19
|
+
# create an application with all the necessary user context
|
17
20
|
def initialize(input, output, error, args)
|
18
|
-
raise ArgumentError, "input"
|
21
|
+
raise ArgumentError, "input" unless input.kind_of? IO
|
19
22
|
raise ArgumentError, "output" unless output.kind_of? IO
|
20
|
-
raise ArgumentError, "error"
|
21
|
-
raise ArgumentError, "args"
|
23
|
+
raise ArgumentError, "error" unless error.kind_of? IO
|
24
|
+
raise ArgumentError, "args" unless args.kind_of? Array
|
22
25
|
|
23
26
|
@input = input
|
24
27
|
@output = output
|
@@ -27,6 +30,7 @@ class Yay
|
|
27
30
|
@running = false
|
28
31
|
end
|
29
32
|
|
33
|
+
# run the application. when this ends, termination is expected
|
30
34
|
def run
|
31
35
|
raise "already running" if @running
|
32
36
|
@running = true
|
@@ -44,26 +48,40 @@ class Yay
|
|
44
48
|
return if preArg == DO_NOTHING_ARG
|
45
49
|
|
46
50
|
begin
|
47
|
-
|
51
|
+
|
48
52
|
@parser = Yay::Parser.new
|
49
53
|
@parser.allow_all = true
|
50
54
|
@parser.parse_array(@args)
|
51
55
|
@rules = @parser.get_rules
|
52
56
|
|
57
|
+
# the parser may instruct us to shut down
|
58
|
+
if @parser.shutdown
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
53
62
|
@colourizer = Yay::Colourizer.new @rules, @input, @output
|
54
|
-
|
63
|
+
|
55
64
|
if preArg == DUMP_RULES_ARG
|
56
65
|
dump_colours @colourizer.line_rules, @colourizer.part_rules
|
57
66
|
return
|
58
67
|
end
|
59
68
|
|
60
69
|
@colourizer.colourize_pipe
|
70
|
+
|
71
|
+
# provide readable text for internal errors
|
61
72
|
rescue Yay::Error => error
|
62
|
-
@error.puts error.printable_message
|
73
|
+
@error.puts "#{ColourWheel::fail}#{error.printable_message}#{ColourWheel::end_colour}"
|
74
|
+
|
75
|
+
# catch ctrl+c and similar events
|
63
76
|
rescue Interrupt
|
64
77
|
end
|
78
|
+
|
79
|
+
# emit the end colour just in case we were interrupted
|
80
|
+
print ColourWheel.end_colour
|
65
81
|
end
|
66
82
|
|
83
|
+
# with the --dump command we can see the resulting rules created by the
|
84
|
+
# rule definitions (from all files included too)
|
67
85
|
def dump_colours line_rules, word_rules
|
68
86
|
|
69
87
|
puts "line rules:" if line_rules
|
data/lib/yay/colour_wheel.rb
CHANGED
@@ -1,58 +1,72 @@
|
|
1
|
-
# To change this template, choose Tools | Templates
|
2
|
-
# and open the template in the editor.
|
3
|
-
|
4
1
|
class Yay
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
2
|
+
# the colour wheel contains all the constants needed to create coloured text
|
3
|
+
# there are also a few static helper methods to make rendering text easier
|
4
|
+
class ColourWheel
|
5
|
+
|
6
|
+
# commands. support varies
|
7
|
+
MISC = {
|
8
|
+
:reset => 0,
|
9
|
+
:bright => 1,
|
10
|
+
:dim => 2,
|
11
|
+
:underscore => 4,
|
12
|
+
:blink => 5,
|
13
|
+
:reverse => 7,
|
14
|
+
:hidden => 8,
|
15
|
+
|
16
|
+
:normal => 0, #alias
|
17
|
+
:invert => 7, #alias
|
18
|
+
:inverted => 7, #alias
|
19
|
+
:underscored => 4, #alias
|
20
|
+
}
|
21
|
+
|
22
|
+
# foreground colours
|
23
|
+
FG = {
|
24
|
+
:black => 30,
|
25
|
+
:red => 31,
|
26
|
+
:green => 32,
|
27
|
+
:yellow => 33,
|
28
|
+
:blue => 34,
|
29
|
+
:magenta => 35,
|
30
|
+
:cyan => 36,
|
31
|
+
:white => 37,
|
32
|
+
};
|
33
|
+
|
34
|
+
# background colours
|
35
|
+
BG = {
|
36
|
+
:black => 40,
|
37
|
+
:red => 41,
|
38
|
+
:green => 42,
|
39
|
+
:yellow => 43,
|
40
|
+
:blue => 44,
|
41
|
+
:magenta => 45,
|
42
|
+
:cyan => 46,
|
43
|
+
:white => 47
|
44
|
+
};
|
45
|
+
|
46
|
+
# return all the possible colour names
|
47
|
+
# the keys are used as string representations by the parser
|
48
|
+
def self.all_names
|
49
|
+
# assume BG and FG have the same keys
|
50
|
+
MISC.keys | FG.keys
|
51
|
+
end
|
52
|
+
|
53
|
+
# ge the string that begins the current colour code
|
54
|
+
def self.begin_colours(colour_numbers)
|
55
|
+
"\033[#{colour_numbers.join(';')}m"
|
56
|
+
end
|
57
|
+
|
58
|
+
# the command necessary to stop printing with colour
|
59
|
+
def self.end_colour
|
60
|
+
"\033[0m"
|
61
|
+
end
|
62
|
+
|
63
|
+
# ge the string that begins the current colour code
|
64
|
+
def self.success
|
65
|
+
self.begin_colours([FG[:green]])
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.fail()
|
69
|
+
self.begin_colours([FG[:red]])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/yay/colourizer.rb
CHANGED
@@ -1,21 +1,32 @@
|
|
1
1
|
require 'yay/colour_wheel'
|
2
2
|
|
3
3
|
class Yay
|
4
|
+
# this class adds colour to a stream based on rules that have been generated
|
5
|
+
# by a parser
|
4
6
|
class Colourizer
|
7
|
+
# create a colourizer using specified parser rules and input and output
|
8
|
+
# streams (usually stdin/stdout)
|
5
9
|
def initialize rules, input, output
|
6
10
|
colourize_rules rules
|
7
11
|
@input = input
|
8
12
|
@output = output
|
9
13
|
end
|
10
14
|
|
15
|
+
# get the rules that are applied to a whole line if it contains matching text
|
16
|
+
# of the form [[regex, colour_string],..]
|
11
17
|
def line_rules
|
12
18
|
@line_rules
|
13
19
|
end
|
14
20
|
|
21
|
+
# get the rules that are applied to matching text
|
22
|
+
# of the form [[regex, colour_string],..]
|
15
23
|
def part_rules
|
16
24
|
@part_rules
|
17
25
|
end
|
18
26
|
|
27
|
+
# process the rules created by a parser and determine the actual strings we
|
28
|
+
# need to emit when we use this colour. this breaks parser rules up in to
|
29
|
+
# two categories - line rules and part rules
|
19
30
|
def colourize_rules rules
|
20
31
|
@line_rules = []
|
21
32
|
@part_rules = []
|
@@ -36,25 +47,32 @@ class Yay
|
|
36
47
|
}
|
37
48
|
end
|
38
49
|
|
50
|
+
# create a pipe between the input and output streams, applying colour rules
|
51
|
+
# to every line that appears. only an interrupt, end of file or exception
|
52
|
+
# will end this process
|
39
53
|
def colourize_pipe
|
54
|
+
# this is the colour we'll use when we haven't already applied a colour
|
55
|
+
# we remember the previous colour as we can colourize words within a line
|
56
|
+
# that's already been coloured
|
40
57
|
default_end_colour = ColourWheel::end_colour
|
41
58
|
|
42
59
|
@input.each_line { |line|
|
43
60
|
|
44
|
-
# track the line_rules end colour so we can return to this after each
|
61
|
+
# track the line_rules end colour so we can return to this after each
|
62
|
+
# match
|
45
63
|
end_colour = default_end_colour
|
46
64
|
|
47
|
-
#
|
65
|
+
# apply all line rules
|
48
66
|
@line_rules.each { |rule|
|
49
67
|
if line.match(rule[0])
|
50
68
|
line = "#{rule[1]}#{line.rstrip}#{default_end_colour}"
|
51
69
|
end_colour = rule[1]
|
52
|
-
# only allow one line
|
70
|
+
# leave loop; only allow one line match per line
|
53
71
|
break
|
54
72
|
end
|
55
73
|
}
|
56
74
|
|
57
|
-
#
|
75
|
+
# apply all partial rules
|
58
76
|
@part_rules.each { |rule|
|
59
77
|
line.gsub!(rule[0], "#{rule[1]}\\0#{end_colour}")
|
60
78
|
}
|
data/lib/yay/errors.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
|
2
2
|
class Yay
|
3
|
+
# the base class for errors in yay. this provides error reporting in a
|
4
|
+
# friendly way (who likes stack traces?)
|
3
5
|
class Error < StandardError
|
4
|
-
|
6
|
+
attr_reader :position
|
5
7
|
|
8
|
+
# override this to provide user feedback
|
6
9
|
def printable_message
|
7
10
|
raise "Unimplemented printable error"
|
8
11
|
end
|
9
12
|
|
13
|
+
# a generic representation of the error's location on the line, file, etc
|
10
14
|
def printable_position
|
11
15
|
array = @position
|
12
16
|
return "" unless @position
|
13
|
-
length = array.length
|
14
17
|
return " in file #{array[2]}, line #{array[1]}, word #{array[0]}" if array[2]
|
15
18
|
return " on line #{array[1]}, word #{array[0]}" if array[1]
|
16
19
|
return " at word #{array[0]}" if array[0]
|
@@ -18,8 +21,47 @@ class Yay
|
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
24
|
+
# thrown when an invalid filename was entered
|
25
|
+
class BadFilenameError < Error
|
26
|
+
attr_reader :value
|
27
|
+
attr_reader :message
|
28
|
+
|
29
|
+
def initialize value
|
30
|
+
@value = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def printable_message
|
34
|
+
return "Invalid filename #{value} entered"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# this error wraps an underlying error
|
39
|
+
class InstallFailedError < Error
|
40
|
+
MAX_LENGTH = 1028
|
41
|
+
|
42
|
+
attr_reader :error
|
43
|
+
attr_reader :url
|
44
|
+
attr_reader :content
|
45
|
+
|
46
|
+
def initialize url, error, content=nil
|
47
|
+
@url = url
|
48
|
+
@error = error
|
49
|
+
@content = content
|
50
|
+
@content = 'empty' if (content==nil||content.strip=="")
|
51
|
+
if @content.length >= InstallFailedError::MAX_LENGTH
|
52
|
+
@content = "#{@content.slice(0,InstallFailedError::MAX_LENGTH)}\n.."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def printable_message
|
57
|
+
return "Failed to download and install file from #{url}\nReason: #{error}\nResponse was:\n#{content}\nCheck your url!"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# this error is raised when a variable has already been assigned a value
|
62
|
+
# for example @x is red and @x is blue
|
21
63
|
class AlreadyAssignedError < Error
|
22
|
-
|
64
|
+
attr_reader :variable
|
23
65
|
|
24
66
|
def initialize variable
|
25
67
|
@variable = variable
|
@@ -30,9 +72,12 @@ class Yay
|
|
30
72
|
end
|
31
73
|
end
|
32
74
|
|
75
|
+
# this is a generic access control error that's raised when someoen tries to
|
76
|
+
# do something disallowed in their current context. for example, you can
|
77
|
+
# use the install command from the command line but not a yayfile
|
33
78
|
class NotAllowedError < Error
|
34
|
-
|
35
|
-
|
79
|
+
attr_reader :action
|
80
|
+
attr_reader :path
|
36
81
|
|
37
82
|
def initialize action, path
|
38
83
|
@action = action
|
@@ -44,22 +89,26 @@ class Yay
|
|
44
89
|
end
|
45
90
|
end
|
46
91
|
|
92
|
+
# raised when there's a circular reference between rules. this happens when
|
93
|
+
# variables point back to themselves in some way. e.g. @x is @y and @y is @x
|
47
94
|
class CircularReferenceError < Error
|
48
|
-
|
49
|
-
|
95
|
+
attr_reader :current
|
96
|
+
attr_reader :path
|
50
97
|
|
51
98
|
def initialize current, path
|
52
99
|
@current = current
|
53
100
|
@path = path
|
54
101
|
end
|
55
|
-
|
102
|
+
|
56
103
|
def printable_message
|
57
104
|
return "There is a circular reference between variables: #{path.join(' => ')} => #{current}#{printable_position}"
|
58
105
|
end
|
59
106
|
end
|
60
107
|
|
108
|
+
# raised when a variable has been referenced but not given a value. for example
|
109
|
+
# cheese is @x without ever defining what @x is
|
61
110
|
class UnresolvedSubstitutionError < Error
|
62
|
-
|
111
|
+
attr_reader :variable
|
63
112
|
|
64
113
|
def initialize variable
|
65
114
|
@variable = variable
|
@@ -70,9 +119,10 @@ class Yay
|
|
70
119
|
end
|
71
120
|
end
|
72
121
|
|
122
|
+
# raised when include file resolution has failed
|
73
123
|
class CouldntFindFileError < Error
|
74
|
-
|
75
|
-
|
124
|
+
attr_reader :filename
|
125
|
+
attr_reader :tried
|
76
126
|
|
77
127
|
def initialize filename, tried
|
78
128
|
@filename = filename
|
@@ -84,10 +134,13 @@ class Yay
|
|
84
134
|
end
|
85
135
|
end
|
86
136
|
|
137
|
+
# raised when a colour sequence was malformed. in practice you can use
|
138
|
+
# infinite colour commands but zero to two actual colours, the first one will
|
139
|
+
# be the foreground and the second one will be the background
|
87
140
|
class TooManyColoursError < Error
|
88
|
-
|
89
|
-
|
90
|
-
|
141
|
+
attr_reader :fg
|
142
|
+
attr_reader :bg
|
143
|
+
attr_reader :colour
|
91
144
|
|
92
145
|
def initialize fg, bg, colour, position
|
93
146
|
@fg = fg
|
@@ -101,9 +154,12 @@ class Yay
|
|
101
154
|
end
|
102
155
|
end
|
103
156
|
|
157
|
+
# raised when an unexpected token was found by the parser. in otherwords,
|
158
|
+
# the rules of the syntax have been broken somehow and the user hasn't written
|
159
|
+
# a valid command
|
104
160
|
class UnexpectedTokenError < Error
|
105
|
-
|
106
|
-
|
161
|
+
attr_reader :type
|
162
|
+
attr_reader :value
|
107
163
|
|
108
164
|
def initialize type, value, position
|
109
165
|
@type = type
|
@@ -111,12 +167,16 @@ class Yay
|
|
111
167
|
@position = position
|
112
168
|
end
|
113
169
|
|
170
|
+
# add extra feedback for some tokens. help the user out!
|
114
171
|
def extra_message
|
115
172
|
return "Since #{value} has a special meaning, try enclosing it in quotes or a regex when searching for it" if type == "colour"
|
173
|
+
return "Have you finished the line off properly?" if type == "$end"
|
116
174
|
return ""
|
117
175
|
end
|
118
176
|
|
119
177
|
def printable_message
|
178
|
+
return "Unexpected text \"#{value}\"#{printable_position}\n#{extra_message}" if type == "error"
|
179
|
+
return "Unexpected end of line#{printable_position}\n#{extra_message}" if type == "$end"
|
120
180
|
return "Unexpected #{type} \"#{value}\"#{printable_position}\n#{extra_message}"
|
121
181
|
end
|
122
182
|
end
|
data/lib/yay/installer.rb
CHANGED
@@ -1,12 +1,135 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'yay/paths'
|
5
|
+
require 'fileutils'
|
1
6
|
|
2
7
|
class Yay
|
8
|
+
# installs .yay files from a remote url in to either ~/.yay or /etc/yay
|
9
|
+
# depending on the users permissions
|
3
10
|
class Installer
|
4
|
-
|
5
|
-
|
11
|
+
|
12
|
+
# initialize an installer for the specified url. the .install method will
|
13
|
+
# attempt the actual installation process
|
14
|
+
def initialize file_name, url
|
15
|
+
# directories to iterate. begin with /etc/yay, which should only be
|
16
|
+
# accessible to sudo. then try a local install.
|
17
|
+
paths = Yay::Paths.new
|
18
|
+
validate_filename file_name
|
19
|
+
@file_name = append_filetype file_name
|
20
|
+
@dirs = [
|
21
|
+
paths.global_yay_path,
|
22
|
+
paths.local_yay_path
|
23
|
+
]
|
24
|
+
@url = url
|
25
|
+
end
|
26
|
+
|
27
|
+
# some filenames just aren't a good idea
|
28
|
+
def validate_filename string
|
29
|
+
raise BadFilenameError.new string if /[\?\*\\\/]/.match(string)
|
30
|
+
end
|
31
|
+
|
32
|
+
# add the .yay part to the filename if it's missing
|
33
|
+
def append_filetype string
|
34
|
+
return "#{string}.yay" unless /\.yay$/.match(string)
|
35
|
+
return string
|
36
|
+
end
|
37
|
+
|
38
|
+
# see if we can write to a directory. will try to create the folder (and
|
39
|
+
# its parents) unless asked otherwise
|
40
|
+
def can_write_to_dir dir, create
|
41
|
+
|
42
|
+
begin
|
43
|
+
stat = File.stat(dir)
|
44
|
+
return true if stat && stat.writable?
|
45
|
+
rescue Errno::ENOENT
|
46
|
+
end
|
47
|
+
|
48
|
+
# create and try again if it doesn't exist
|
49
|
+
if create
|
50
|
+
begin
|
51
|
+
FileUtils.mkdir_p dir
|
52
|
+
#FileUtils.chmod 0644, dir
|
53
|
+
result = can_write_to_dir dir, false
|
54
|
+
puts "Created #{dir}" if result
|
55
|
+
return result
|
56
|
+
rescue Errno::EACCES
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
# try to find the install directory
|
64
|
+
def get_install_directory
|
65
|
+
# search globally and then locally to see if we can write
|
66
|
+
@dirs.each { |dir|
|
67
|
+
return dir if can_write_to_dir dir, true
|
68
|
+
}
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# make a curl-ish request and get the contents
|
73
|
+
def get_remote_string url, limit=5
|
74
|
+
raise InstallFailedError.new url, 'HTTP redirect too deep' if limit == 0
|
75
|
+
|
76
|
+
begin
|
77
|
+
puts "Requesting #{url}"
|
78
|
+
url = URI.parse(url)
|
79
|
+
|
80
|
+
request = Net::HTTP::Get.new(url.path || '/')
|
81
|
+
|
82
|
+
http = Net::HTTP.new url.host, url.port
|
83
|
+
#http.set_debug_output($stderr)
|
84
|
+
http.use_ssl = url.scheme == 'https'
|
85
|
+
|
86
|
+
response = http.start { |http2|
|
87
|
+
http2.request(request)
|
88
|
+
}
|
89
|
+
|
90
|
+
rescue StandardError => error
|
91
|
+
raise InstallFailedError.new url, error.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
case response
|
95
|
+
when Net::HTTPSuccess then
|
96
|
+
return response.body
|
97
|
+
when Net::HTTPRedirection then
|
98
|
+
puts "Redirecting to #{response['location']}";
|
99
|
+
return get_remote_string(response['location'], limit - 1)
|
100
|
+
end
|
101
|
+
|
102
|
+
raise InstallFailedError.new url, "#{response.code} \"#{response.message}\"", response.body
|
103
|
+
end
|
104
|
+
|
105
|
+
# ensure the rules we've downloaded parse correctly
|
106
|
+
def verify_rules url, string
|
107
|
+
begin
|
108
|
+
parser = Yay::Parser.new
|
109
|
+
parser.parse(string)
|
110
|
+
rescue Yay::Error => error
|
111
|
+
raise InstallFailedError.new url, error.printable_message, string
|
112
|
+
end
|
113
|
+
raise InstallFailedError.new url, "No rules in downloaded file", string if parser.get_rules == []
|
114
|
+
return parser
|
115
|
+
end
|
116
|
+
|
117
|
+
# store a string
|
118
|
+
def install_string string, dest_folder
|
119
|
+
dest = "#{dest_folder}/#{@file_name}"
|
120
|
+
File.open(dest, 'w') {|file|
|
121
|
+
file.write(string)
|
122
|
+
}
|
123
|
+
puts "#{ColourWheel::success}Installed to #{dest}#{ColourWheel::end_colour}"
|
6
124
|
end
|
7
125
|
|
126
|
+
# attempt the installation process
|
8
127
|
def install
|
9
|
-
|
128
|
+
dest_folder = get_install_directory
|
129
|
+
raise "Couldn't write to or create directories #{@dirs.join(' or ')} something is up with your system!" unless dest_folder
|
130
|
+
string = get_remote_string @url
|
131
|
+
verify_rules @url, string
|
132
|
+
install_string string, dest_folder
|
10
133
|
end
|
11
134
|
end
|
12
135
|
end
|
data/lib/yay/lexer.rb
CHANGED
@@ -2,11 +2,12 @@ require 'strscan'
|
|
2
2
|
require 'yay/lexer_regex'
|
3
3
|
|
4
4
|
class Yay
|
5
|
+
# tokenises yay rules
|
5
6
|
class Lexer
|
6
7
|
attr :context_name
|
7
8
|
|
8
9
|
def initialize(string="", context_name=nil)
|
9
|
-
@position =
|
10
|
+
@position = 1
|
10
11
|
@line = 1
|
11
12
|
@context_name = context_name
|
12
13
|
|
@@ -15,19 +16,23 @@ class Yay
|
|
15
16
|
use_string(string)
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
# the context name describes the source yay rules. this is free-form
|
20
|
+
# text but is best set to the filename
|
21
|
+
def context_name= value
|
22
|
+
@context_name = value
|
23
|
+
end
|
21
24
|
|
22
25
|
# take a string and begin scanning it
|
23
26
|
def use_string(string)
|
24
27
|
@scanner = StringScanner.new string
|
25
28
|
end
|
26
29
|
|
30
|
+
# return the current word
|
27
31
|
def position
|
28
32
|
@position
|
29
33
|
end
|
30
34
|
|
35
|
+
# return the current line
|
31
36
|
def line
|
32
37
|
@line
|
33
38
|
end
|
data/lib/yay/lexer_regex.rb
CHANGED
@@ -27,6 +27,9 @@ class Yay
|
|
27
27
|
[:literal , /\b\S+\b/],
|
28
28
|
]
|
29
29
|
|
30
|
+
# get the regular expressions we need. always use this instead of
|
31
|
+
# referencing the base patterns directly as we augment that array with
|
32
|
+
# the colour names that are available
|
30
33
|
def get_patterns
|
31
34
|
patterns = BASE_PATTERNS
|
32
35
|
# add the colour keywords. generate these from the colour wheel's constants
|
data/lib/yay/lister.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'yay/paths'
|
2
|
+
|
3
|
+
class Yay
|
4
|
+
# Lists installed .yay files
|
5
|
+
# See also: Rimmer, Cat
|
6
|
+
class Lister
|
7
|
+
|
8
|
+
# returns [[name, path],..]
|
9
|
+
def get_files_in_dir dir
|
10
|
+
results = []
|
11
|
+
Dir.glob("#{dir}/*.yay").each { |path|
|
12
|
+
matches = /\/(\w*)?\.yay$/.match(path)
|
13
|
+
if matches[1]
|
14
|
+
results.unshift [matches[1], path]
|
15
|
+
else
|
16
|
+
puts "Eh.. #{path} isn't quite right"
|
17
|
+
end
|
18
|
+
}
|
19
|
+
return results
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns {dir=>[file,..]
|
23
|
+
def get_all_files
|
24
|
+
paths = Yay::Paths.new
|
25
|
+
result = {}
|
26
|
+
paths.yay_paths.each { |path|
|
27
|
+
result[path] = get_files_in_dir path
|
28
|
+
}
|
29
|
+
return result
|
30
|
+
end
|
31
|
+
|
32
|
+
# print the search paths we'll use when looking for yay files
|
33
|
+
def print_paths
|
34
|
+
puts "Search paths: (in order of precedence)"
|
35
|
+
paths = Yay::Paths.new
|
36
|
+
paths.yay_paths.each { |dir|
|
37
|
+
puts dir
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
# print the files we can use and the command that can be typed to use it
|
42
|
+
def print_files
|
43
|
+
puts "Installed styles:"
|
44
|
+
get_all_files.each_pair { |dir, files|
|
45
|
+
#puts "#{dir}:"
|
46
|
+
files.each { |file|
|
47
|
+
puts "#{file[0]}#{' '*(20-file[0].length)}#{file[1]}"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# print all paths and files we find in them
|
53
|
+
def print
|
54
|
+
print_paths
|
55
|
+
puts
|
56
|
+
print_files
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/yay/loader.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'yay/paths'
|
2
2
|
|
3
3
|
class Yay
|
4
|
+
# resolves the location of an include file
|
4
5
|
class Loader
|
5
6
|
def initialize filename
|
6
7
|
@filename = filename
|
7
8
|
end
|
8
9
|
|
10
|
+
# get the default loader. this, um, loads the default.yay file!
|
9
11
|
def self.default_file_loader
|
10
12
|
return Yay::Loader.new Yay::Paths::DEFAULT_YAYFILE
|
11
13
|
end
|
data/lib/yay/parser.rb
CHANGED
@@ -6,150 +6,175 @@ require 'yay/loader'
|
|
6
6
|
require 'yay/installer'
|
7
7
|
require 'yay/errors'
|
8
8
|
require 'yay/paths'
|
9
|
+
require 'yay/lister'
|
9
10
|
|
10
11
|
class Yay
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
# extends the parser that was automatically generated by racc and adds the
|
13
|
+
# behaviour necessary. this separation is done only because it's difficult to
|
14
|
+
# use .y files for anything other than grammar rules, even if they do allow
|
15
|
+
# ruby code
|
16
|
+
class Parser < Yay::ParserGen
|
17
|
+
|
18
|
+
# allow this parser to load the default rule file if the rule body is empty
|
19
|
+
attr_accessor :allow_default
|
20
|
+
|
21
|
+
# allow this parser to install new rule files from remote sources. beware
|
22
|
+
# the consequences. this should be allowed from the command line only!
|
23
|
+
attr_accessor :allow_install
|
24
|
+
|
25
|
+
# allow this parser to include rule files that are installed. including
|
26
|
+
# ones in the gem folders, globally and locally
|
27
|
+
attr_accessor :allow_include
|
28
|
+
|
29
|
+
# allow this parser to search for and print out all the rules that are
|
30
|
+
# installed
|
31
|
+
attr_accessor :allow_list
|
32
|
+
|
33
|
+
# set to true to signal to the application or parent parser that it's time
|
34
|
+
# to shut down
|
35
|
+
attr_reader :shutdown
|
16
36
|
|
17
37
|
def initialize context_name=nil
|
18
|
-
|
38
|
+
@lexer = Yay::Lexer.new
|
19
39
|
@lexer.context_name = context_name
|
20
40
|
end
|
21
41
|
|
22
|
-
def allow_include= value
|
23
|
-
@allow_include = value
|
24
|
-
end
|
25
|
-
|
26
42
|
# load a file from a url
|
27
|
-
|
43
|
+
def include_file filename
|
28
44
|
raise NotAllowedError.new "include #{filename}", current_position unless @allow_include
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
45
|
+
loader = Yay::Loader.new filename
|
46
|
+
loader.load
|
47
|
+
@ruleset.merge loader.get_rules
|
48
|
+
end
|
33
49
|
|
34
50
|
# install a file from a url
|
35
|
-
|
51
|
+
def install_file file_name, url
|
36
52
|
raise NotAllowedError.new "install #{url}", current_position unless @allow_install
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
53
|
+
installer = Yay::Installer.new file_name, url
|
54
|
+
installer.install
|
55
|
+
@shutdown = true
|
56
|
+
end
|
57
|
+
|
41
58
|
# print the full list of yay files
|
42
|
-
|
43
|
-
raise NotAllowedError.new "list installed yay files", current_position unless @
|
44
|
-
|
45
|
-
|
46
|
-
|
59
|
+
def list_installed
|
60
|
+
raise NotAllowedError.new "list installed yay files", current_position unless @allow_list
|
61
|
+
lister = Yay::Lister.new
|
62
|
+
lister.print
|
63
|
+
@shutdown = true
|
64
|
+
end
|
65
|
+
|
47
66
|
# allow all parser actions
|
48
67
|
def allow_all= value
|
49
|
-
@allow_default = @allow_install = @allow_include = @
|
68
|
+
@allow_default = @allow_install = @allow_include = @allow_list = value
|
50
69
|
end
|
51
70
|
|
52
71
|
# load the default file. used when the commandline is empty
|
53
72
|
def use_default_file
|
54
73
|
# don't throw an error in this case. it's legitimate for a file to be empty
|
55
74
|
return unless @allow_default
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
# a regular expression and convert it in to a bytewise options variable
|
72
|
-
def extract_regexp_options args
|
73
|
-
return 0 if args.nil?
|
74
|
-
raise ArgumentError unless args.kind_of? String
|
75
|
-
options_map = {
|
76
|
-
'i' => Regexp::IGNORECASE,
|
77
|
-
'm' => Regexp::MULTILINE,
|
78
|
-
'x' => Regexp::EXTENDED,
|
79
|
-
}
|
80
|
-
options = 0
|
81
|
-
args.each { |char|
|
82
|
-
options |= options_map[char] || 0
|
83
|
-
}
|
84
|
-
return options
|
85
|
-
end
|
86
|
-
|
87
|
-
# for lack of a better function, this will take a string like "/abc/" and
|
88
|
-
# transform it in to a regex object
|
89
|
-
def string_to_regex string, escape=true
|
90
|
-
matches = /\/([^\/\\\r\n]*(?:\\.[^\/\\\r\n]*)*)\/([a-z]\b)*/.match string
|
91
|
-
return nil if matches[1].nil?
|
92
|
-
content = matches[1]
|
93
|
-
content = Regexp::escape(content) if escape
|
94
|
-
options = extract_regexp_options matches[2]
|
95
|
-
return Regexp.new(content, options)
|
96
|
-
end
|
97
|
-
|
98
|
-
# given an array of colour strings, create an array with the VT100 colour
|
99
|
-
# sequences inside
|
100
|
-
def handle_colours colours
|
101
|
-
fg = bg = nil
|
102
|
-
result = []
|
103
|
-
# iterate the colour list and try to find up to two colours (foreground,
|
104
|
-
# background) and unlimited miscellaneous colours (reset, invert, etc)
|
105
|
-
colours.each { |colour|
|
106
|
-
misc_val = ColourWheel::MISC[colour]
|
107
|
-
if !misc_val.nil?
|
108
|
-
result.push misc_val
|
109
|
-
elsif !fg
|
110
|
-
fg = ColourWheel::FG[colour]
|
111
|
-
result.push fg
|
112
|
-
elsif !bg
|
113
|
-
bg = ColourWheel::BG[colour]
|
114
|
-
result.push bg
|
115
|
-
else
|
116
|
-
raise Yay::TooManyColoursError.new fg, bg, colour, current_position
|
117
|
-
end
|
118
|
-
}
|
119
|
-
result
|
120
|
-
end
|
121
|
-
|
122
|
-
def get_rules
|
123
|
-
@ruleset.get_rules
|
124
|
-
end
|
125
|
-
|
126
|
-
# process commandline arguments as if they were from a yay file
|
127
|
-
def parse_array args
|
128
|
-
raise ArgumentError, "args" unless args.kind_of? Array
|
129
|
-
parse args.join(' ')
|
130
|
-
end
|
131
|
-
|
132
|
-
# parse a string
|
133
|
-
def parse(str)
|
134
|
-
@lexer.use_string(str)
|
135
|
-
@ruleset = Yay::RuleSet.new
|
136
|
-
|
137
|
-
do_parse
|
138
|
-
get_rules
|
139
|
-
end
|
140
|
-
|
141
|
-
# get the next token
|
142
|
-
def next_token
|
143
|
-
@lexer.next_token
|
144
|
-
end
|
75
|
+
loader = Yay::Loader.default_file_loader
|
76
|
+
loader.load
|
77
|
+
@ruleset.merge loader.get_rules
|
78
|
+
end
|
79
|
+
|
80
|
+
# process a string token in to something we can use
|
81
|
+
def handle_string string
|
82
|
+
string = Regexp::escape(string)
|
83
|
+
return Regexp.new(string, Regexp::IGNORECASE)
|
84
|
+
end
|
85
|
+
|
86
|
+
# process a regex token in to something we can use
|
87
|
+
def handle_regex string
|
88
|
+
return string_to_regex string, false
|
89
|
+
end
|
145
90
|
|
91
|
+
# for lack of a better function, this will take the ending sequence from
|
92
|
+
# a regular expression and convert it in to a bytewise options variable
|
93
|
+
def extract_regexp_options args
|
94
|
+
return 0 if args.nil?
|
95
|
+
raise ArgumentError unless args.kind_of? String
|
96
|
+
options_map = {
|
97
|
+
'i' => Regexp::IGNORECASE,
|
98
|
+
'm' => Regexp::MULTILINE,
|
99
|
+
'x' => Regexp::EXTENDED,
|
100
|
+
}
|
101
|
+
options = 0
|
102
|
+
args.each { |char|
|
103
|
+
options |= options_map[char] || 0
|
104
|
+
}
|
105
|
+
return options
|
106
|
+
end
|
107
|
+
|
108
|
+
# for lack of a better function, this will take a string like "/abc/" and
|
109
|
+
# transform it in to a regex object
|
110
|
+
def string_to_regex string, escape=true
|
111
|
+
matches = /\/([^\/\\\r\n]*(?:\\.[^\/\\\r\n]*)*)\/([a-z]\b)*/.match string
|
112
|
+
return nil if matches[1].nil?
|
113
|
+
content = matches[1]
|
114
|
+
content = Regexp::escape(content) if escape
|
115
|
+
options = extract_regexp_options matches[2]
|
116
|
+
return Regexp.new(content, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
# given an array of colour strings, create an array with the VT100 colour
|
120
|
+
# sequences inside
|
121
|
+
def handle_colours colours
|
122
|
+
fg = bg = nil
|
123
|
+
result = []
|
124
|
+
# iterate the colour list and try to find up to two colours (foreground,
|
125
|
+
# background) and unlimited miscellaneous colours (reset, invert, etc)
|
126
|
+
colours.each { |colour|
|
127
|
+
misc_val = ColourWheel::MISC[colour]
|
128
|
+
if !misc_val.nil?
|
129
|
+
result.push misc_val
|
130
|
+
elsif !fg
|
131
|
+
fg = ColourWheel::FG[colour]
|
132
|
+
result.push fg
|
133
|
+
elsif !bg
|
134
|
+
bg = ColourWheel::BG[colour]
|
135
|
+
result.push bg
|
136
|
+
else
|
137
|
+
raise Yay::TooManyColoursError.new fg, bg, colour, current_position
|
138
|
+
end
|
139
|
+
}
|
140
|
+
result
|
141
|
+
end
|
142
|
+
|
143
|
+
# get the end result of the parse
|
144
|
+
def get_rules
|
145
|
+
@ruleset.get_rules
|
146
|
+
end
|
147
|
+
|
148
|
+
# process commandline arguments as if they were from a yay file
|
149
|
+
def parse_array args
|
150
|
+
raise ArgumentError, "args" unless args.kind_of? Array
|
151
|
+
parse args.join(' ')
|
152
|
+
end
|
153
|
+
|
154
|
+
# parse a string. returns the results
|
155
|
+
def parse(str)
|
156
|
+
@lexer.use_string(str)
|
157
|
+
@ruleset = Yay::RuleSet.new
|
158
|
+
|
159
|
+
do_parse
|
160
|
+
return get_rules
|
161
|
+
end
|
162
|
+
|
163
|
+
# get the next token
|
164
|
+
def next_token
|
165
|
+
@lexer.next_token
|
166
|
+
end
|
167
|
+
|
168
|
+
# get location information from the lexer in a nice little array we can
|
169
|
+
# pass to an exception constructor
|
146
170
|
def current_position
|
147
171
|
return [@lexer.position, @lexer.line, @lexer.context_name]
|
148
172
|
end
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
173
|
+
|
174
|
+
# the racc on_error function
|
175
|
+
def on_error error_token_id, error_value, cant_touch_this
|
176
|
+
type = token_to_str error_token_id
|
177
|
+
raise Yay::UnexpectedTokenError.new type, error_value, current_position
|
178
|
+
end
|
179
|
+
end
|
155
180
|
end
|
data/lib/yay/parser_gen.rb
CHANGED
@@ -15,37 +15,39 @@ module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 54)
|
|
15
15
|
##### State transition tables begin ###
|
16
16
|
|
17
17
|
racc_action_table = [
|
18
|
-
-7, -25,
|
19
|
-
|
20
|
-
10, 12, 28,
|
21
|
-
29,
|
18
|
+
-7, -25, 33, 17, 25, 17, -25, 12, 22, 22,
|
19
|
+
33, 20, 30, 9, 10, 12, 2, 4, 8, 9,
|
20
|
+
10, 12, 28, 36, 31, 29, 29, 19, -2, 17,
|
21
|
+
38, 29, 38 ]
|
22
22
|
|
23
23
|
racc_action_check = [
|
24
24
|
7, 6, 21, 17, 10, 9, 6, 21, 6, 7,
|
25
25
|
23, 4, 19, 23, 23, 23, 0, 0, 0, 0,
|
26
|
-
0, 0, 18, 24,
|
27
|
-
29,
|
26
|
+
0, 0, 18, 24, 20, 18, 24, 3, 2, 1,
|
27
|
+
27, 29, 35 ]
|
28
28
|
|
29
29
|
racc_action_pointer = [
|
30
|
-
14,
|
30
|
+
14, 18, 28, 27, 9, nil, -1, 0, nil, -6,
|
31
31
|
2, nil, nil, nil, nil, nil, nil, -8, 17, 12,
|
32
|
-
|
33
|
-
nil, nil, nil, nil,
|
32
|
+
22, 0, nil, 8, 18, nil, nil, 20, nil, 23,
|
33
|
+
nil, nil, nil, nil, nil, 22, nil, nil, nil, nil,
|
34
|
+
nil ]
|
34
35
|
|
35
36
|
racc_action_default = [
|
36
37
|
-5, -29, -20, -30, -30, -1, -19, -25, -4, -29,
|
37
38
|
-30, -8, -21, -9, -10, -11, -12, -29, -30, -30,
|
38
|
-
|
39
|
-
|
39
|
+
-30, -30, -24, -30, -30, -17, -28, -27, -14, -23,
|
40
|
+
41, -3, -18, -20, -6, -27, -16, -13, -26, -22,
|
41
|
+
-15 ]
|
40
42
|
|
41
43
|
racc_goto_table = [
|
42
|
-
5, 18, 27,
|
43
|
-
|
44
|
-
nil, nil, nil,
|
44
|
+
5, 18, 27, 37, 21, 23, 32, 3, 35, 24,
|
45
|
+
nil, 40, nil, 39, nil, nil, nil, 26, nil, nil,
|
46
|
+
nil, nil, nil, 34 ]
|
45
47
|
|
46
48
|
racc_goto_check = [
|
47
49
|
2, 11, 12, 13, 4, 4, 10, 1, 12, 11,
|
48
|
-
13, nil,
|
50
|
+
nil, 13, nil, 12, nil, nil, nil, 11, nil, nil,
|
49
51
|
nil, nil, nil, 2 ]
|
50
52
|
|
51
53
|
racc_goto_pointer = [
|
@@ -60,7 +62,7 @@ racc_reduce_table = [
|
|
60
62
|
0, 0, :racc_error,
|
61
63
|
1, 13, :_reduce_1,
|
62
64
|
1, 13, :_reduce_2,
|
63
|
-
|
65
|
+
3, 13, :_reduce_3,
|
64
66
|
1, 13, :_reduce_4,
|
65
67
|
0, 13, :_reduce_5,
|
66
68
|
3, 14, :_reduce_6,
|
@@ -90,7 +92,7 @@ racc_reduce_table = [
|
|
90
92
|
|
91
93
|
racc_reduce_n = 30
|
92
94
|
|
93
|
-
racc_shift_n =
|
95
|
+
racc_shift_n = 41
|
94
96
|
|
95
97
|
racc_token_table = {
|
96
98
|
false => 0,
|
@@ -177,7 +179,7 @@ module_eval(<<'.,.,', 'grammar.y', 6)
|
|
177
179
|
|
178
180
|
module_eval(<<'.,.,', 'grammar.y', 7)
|
179
181
|
def _reduce_3(val, _values, result)
|
180
|
-
install_file val[1]
|
182
|
+
install_file val[1], val[2]
|
181
183
|
result
|
182
184
|
end
|
183
185
|
.,.,
|
data/lib/yay/paths.rb
CHANGED
@@ -2,10 +2,10 @@ require 'rubygems'
|
|
2
2
|
require 'yay/version'
|
3
3
|
|
4
4
|
class Yay
|
5
|
-
|
5
|
+
|
6
6
|
# some utility functions for finding the current install and .yay paths
|
7
7
|
class Paths
|
8
|
-
|
8
|
+
|
9
9
|
DEFAULT_YAYFILE = 'default'
|
10
10
|
|
11
11
|
# get the paths to installed gems
|
@@ -20,13 +20,17 @@ class Yay
|
|
20
20
|
|
21
21
|
# get all the paths where we might be able to find .yay files
|
22
22
|
def yay_paths
|
23
|
-
result = [local_yay_path]
|
23
|
+
result = [local_yay_path,global_yay_path]
|
24
24
|
gempaths.each { |v|
|
25
25
|
result.push gempath_to_yaypath(v)
|
26
26
|
}
|
27
27
|
return result
|
28
28
|
end
|
29
29
|
|
30
|
+
def global_yay_path
|
31
|
+
return '/etc/yay'
|
32
|
+
end
|
33
|
+
|
30
34
|
# get the path we store local .yay files
|
31
35
|
def local_yay_path
|
32
36
|
raise "ENV[HOME] not found!" unless ENV['HOME']
|
@@ -34,5 +38,5 @@ class Yay
|
|
34
38
|
end
|
35
39
|
|
36
40
|
end
|
37
|
-
|
38
|
-
end
|
41
|
+
|
42
|
+
end
|
data/lib/yay/rule_set.rb
CHANGED
@@ -21,7 +21,8 @@ class Yay
|
|
21
21
|
def merge rules
|
22
22
|
@rules = @rules | rules
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
|
+
# get the rules, complete with variable substitutions made
|
25
26
|
def get_rules
|
26
27
|
# ensure we substitute all variables
|
27
28
|
substitute_variables if @string_to_var
|
@@ -79,6 +80,7 @@ class Yay
|
|
79
80
|
return result
|
80
81
|
end
|
81
82
|
|
83
|
+
# replace all references to variables with their actual colours
|
82
84
|
def substitute_variables
|
83
85
|
@string_to_var.each { |ref|
|
84
86
|
string = ref[0]
|
data/lib/yay/version.rb
CHANGED
@@ -2,18 +2,21 @@ require 'open3'
|
|
2
2
|
|
3
3
|
class Yay
|
4
4
|
|
5
|
-
|
5
|
+
# the gem version. increment to make a new release!
|
6
|
+
VERSION = "0.0.6"
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
# yoinked from chef. this gives us the git revision number of the current
|
9
|
+
# build if possible. used for --version
|
10
|
+
def self.version
|
11
|
+
@rev ||= begin
|
12
|
+
begin
|
13
|
+
rev = Open3.popen3("git rev-parse HEAD") {|stdin, stdout, stderr| stdout.read }.strip
|
14
|
+
rescue Errno::ENOENT
|
15
|
+
rev = ""
|
16
|
+
end
|
17
|
+
rev.empty? ? nil : " (#{rev})"
|
18
|
+
end
|
19
|
+
"#{VERSION}#@rev"
|
20
|
+
end
|
18
21
|
|
19
22
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- jon davey
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-11-
|
18
|
+
date: 2011-11-20 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -30,21 +30,22 @@ extra_rdoc_files: []
|
|
30
30
|
files:
|
31
31
|
- LICENSE
|
32
32
|
- data/yay/default.yay
|
33
|
-
- data/yay/syslog.yay
|
34
33
|
- data/yay/log4x.yay
|
35
|
-
-
|
36
|
-
- lib/yay/
|
34
|
+
- data/yay/syslog.yay
|
35
|
+
- lib/yay/colourizer.rb
|
36
|
+
- lib/yay/application.rb
|
37
|
+
- lib/yay/version.rb
|
37
38
|
- lib/yay/parser_gen.rb
|
38
|
-
- lib/yay/
|
39
|
-
- lib/yay/colour_wheel.rb
|
39
|
+
- lib/yay/lister.rb
|
40
40
|
- lib/yay/lexer_regex.rb
|
41
|
-
- lib/yay/
|
42
|
-
- lib/yay/
|
43
|
-
- lib/yay/application.rb
|
41
|
+
- lib/yay/errors.rb
|
42
|
+
- lib/yay/parser.rb
|
44
43
|
- lib/yay/loader.rb
|
45
|
-
- lib/yay/
|
46
|
-
- lib/yay/
|
44
|
+
- lib/yay/paths.rb
|
45
|
+
- lib/yay/colour_wheel.rb
|
47
46
|
- lib/yay/installer.rb
|
47
|
+
- lib/yay/rule_set.rb
|
48
|
+
- lib/yay/lexer.rb
|
48
49
|
- bin/yay
|
49
50
|
has_rdoc: true
|
50
51
|
homepage: http://github.com/jond3k/yay
|