lilutils 0.0.1
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.
- data/History.txt +4 -0
- data/Manifest.txt +22 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +55 -0
- data/Rakefile +53 -0
- data/bin/cli-demo +33 -0
- data/lib/lilutils/algo_test_utils/data_sets.rb +57 -0
- data/lib/lilutils/algo_test_utils_entry.rb +4 -0
- data/lib/lilutils/cli/cli.rb +226 -0
- data/lib/lilutils/cli_entry.rb +4 -0
- data/lib/lilutils/misc/misc.rb +2 -0
- data/lib/lilutils/misc/pascal.rb +21 -0
- data/lib/lilutils/misc_entry.rb +5 -0
- data/lib/lilutils.rb +8 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/algo_test_utils/data_sets_test.rb +12 -0
- data/test/cli/cli_basic_test.rb +126 -0
- data/test/misc/misc_pascal_test.rb +28 -0
- data/test/test_helper.rb +3 -0
- data/test/test_lilutils.rb +8 -0
- metadata +145 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
lib/lilutils.rb
|
7
|
+
lib/lilutils/cli/cli.rb
|
8
|
+
lib/lilutils/cli_entry.rb
|
9
|
+
lib/lilutils/algo_test_utils/data_sets.rb
|
10
|
+
lib/lilutils/algo_test_utils_entry.rb
|
11
|
+
lib/lilutils/misc/misc.rb
|
12
|
+
lib/lilutils/misc/pascal.rb
|
13
|
+
lib/lilutils/misc_entry.rb
|
14
|
+
bin/cli-demo
|
15
|
+
script/console
|
16
|
+
script/destroy
|
17
|
+
script/generate
|
18
|
+
test/test_helper.rb
|
19
|
+
test/test_lilutils.rb
|
20
|
+
test/algo_test_utils/data_sets_test.rb
|
21
|
+
test/cli/cli_basic_test.rb
|
22
|
+
test/misc/misc_pascal_test.rb
|
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
= lilutils
|
2
|
+
|
3
|
+
* http://github.com:kedarmhaswade/lilutils.git
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Provides little utilities that are mainly intended for myself. Maybe someone else would find them useful?
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Provides a CLI module which provides a general purpose selection interface for command line interface.
|
12
|
+
|
13
|
+
|
14
|
+
== SYNOPSIS:
|
15
|
+
|
16
|
+
require 'lilutils/cli'
|
17
|
+
|
18
|
+
yn = YesNo.new
|
19
|
+
|
20
|
+
puts "You chose: #{yn.show}"
|
21
|
+
|
22
|
+
See bin/cli-demo after the gem is installed.
|
23
|
+
|
24
|
+
== REQUIREMENTS:
|
25
|
+
|
26
|
+
* Ruby 1.9.2
|
27
|
+
|
28
|
+
== INSTALL:
|
29
|
+
|
30
|
+
* [sudo] gem install lilutils
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
(The MIT License)
|
35
|
+
|
36
|
+
Copyright (c) 2011 Kedar Mhaswade
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "lilutils"
|
16
|
+
gem.homepage = "http://github.com/kedarmhaswade/lilutils"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Little utilities for everyone}
|
19
|
+
gem.description = %Q{Provides little utilties. It's a gem by a newbie, but I think it is quite useful. As of now, it provides a nicely abstracted out yes/no/cancel dialog box on a console.}
|
20
|
+
gem.email = "kedar.mhaswade@gmail.com"
|
21
|
+
gem.authors = ["Kedar Mhaswade"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |test|
|
38
|
+
test.libs << 'test'
|
39
|
+
test.pattern = 'test/**/test_*.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "lilutils #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/bin/cli-demo
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'lilutils'
|
3
|
+
CLI = LilUtils::CLI
|
4
|
+
yn = CLI::NumberedOption.new(1, "Yes/No")
|
5
|
+
ync = CLI::NumberedOption.new(2, "Yes/No/Cancel")
|
6
|
+
list = CLI::NumberedOptions.new([yn, ync], 0, "Pick your pick for the demo: ", true)
|
7
|
+
puts "You chose: #{list.show}"
|
8
|
+
puts "Now opposite of the above"
|
9
|
+
list = CLI::NumberedOptions.new([yn, ync], 1, "Just press Enter to see what happens", true)
|
10
|
+
puts "You chose: #{list.show}"
|
11
|
+
puts "Now special case of the above"
|
12
|
+
yes_no = CLI::YesNo.new
|
13
|
+
puts "You chose: #{yes_no.show}"
|
14
|
+
puts "Liked it? Then use it!"
|
15
|
+
sc = CLI::Option.new("Show code")
|
16
|
+
ex = CLI::Option.new("Just exit")
|
17
|
+
yn = CLI::OptionList.new([sc, ex], 0, "What do you want me to do?", true)
|
18
|
+
choice = yn.show
|
19
|
+
if choice == sc # show me code
|
20
|
+
puts "-----------------------------------------------------------------------"
|
21
|
+
File.open(__FILE__, "r") do |f|
|
22
|
+
f.readlines.each do |line|
|
23
|
+
puts line
|
24
|
+
end
|
25
|
+
puts "-----------------------------------------------------------------------"
|
26
|
+
end
|
27
|
+
elsif choice == ex # just exit
|
28
|
+
puts "Bye!"
|
29
|
+
exit 0
|
30
|
+
else
|
31
|
+
puts "Impossible!"
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Provides for code useful to test algorithms, do benchmarks etc. For example, you might be testing a sorting algorithm
|
2
|
+
# and need 100_000 or 1_000_000 randomly generated (supposedly unsorted) strings. Of course, you are not going to test
|
3
|
+
# your algorithm with ten or hundred strings or numbers, right?
|
4
|
+
module LilUtils
|
5
|
+
module AlgoTestUtils
|
6
|
+
module DataSets
|
7
|
+
ALPHABET = ('a'..'z').to_a + ('0'..'9').to_a
|
8
|
+
SIZE = ALPHABET.length
|
9
|
+
|
10
|
+
# Returns random strings of <b> equal length </b>.
|
11
|
+
# The length of each string is determined by the parameter passed.
|
12
|
+
# The characters that can appear in returned strings are defined by
|
13
|
+
# the {#ALPHABET}.
|
14
|
+
# @param howmany [Integer] How many random strings do you need?
|
15
|
+
# @param rest [Integer] Optional arguments. First argument should be the length of
|
16
|
+
# each string in returned set. If unspecified, this is calculated from first
|
17
|
+
# argument, howmany, such that the length is enough to generate strings from the
|
18
|
+
# entire ALPHABET.
|
19
|
+
def self.ascii_strings(howmany, *rest)
|
20
|
+
p howmany, rest if $DEBUG
|
21
|
+
raise ArgumentError, "Size must be positive integer" if howmany < 1
|
22
|
+
srand(Time.now.to_i)
|
23
|
+
strings = []
|
24
|
+
of_length = rest[0] ? rest[0] : get_string_length_for(howmany)
|
25
|
+
1.upto howmany do
|
26
|
+
strings << get_ascii_string(of_length)
|
27
|
+
end
|
28
|
+
strings
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.get_ascii_string(length)
|
34
|
+
i = 0
|
35
|
+
str = ""
|
36
|
+
while i < length
|
37
|
+
str << ALPHABET[rand(SIZE)]
|
38
|
+
i += 1
|
39
|
+
end
|
40
|
+
str
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.get_string_length_for(size)
|
44
|
+
length = 0
|
45
|
+
while size > 0
|
46
|
+
length += 1
|
47
|
+
size /= SIZE
|
48
|
+
end
|
49
|
+
length
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# Example:
|
55
|
+
#DataSets = LilUtils::AlgoTestUtils::DataSets
|
56
|
+
#puts DataSets.ascii_strings(10).sort
|
57
|
+
#puts DataSets.ascii_strings(100, 10).sort
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# Adds the simple_name method to Module.
|
2
|
+
# @note A simple_name is just the name of the class/module without encompassing modules
|
3
|
+
class Module
|
4
|
+
# suggested by Brian Candler
|
5
|
+
def simple_name
|
6
|
+
name.gsub(/^.*::/, '')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# The main module, wrapped inside LilUtils
|
11
|
+
# Provides functionality to interact with users on a <i> command line </i>
|
12
|
+
module LilUtils
|
13
|
+
|
14
|
+
module CLI
|
15
|
+
|
16
|
+
# Models an arbitrary option that user has choice to choose. Every Option has a name and a key.
|
17
|
+
# The name of an Option is its given name capitalized and its key is first character in its name in lower case. For example,
|
18
|
+
# for an option constructed with the string "separate", the actual name is "Separate" and key is 's'.
|
19
|
+
# Provides behavior for such an Option as far as its display, equality, validity etc. is
|
20
|
+
# concerned.
|
21
|
+
class Option
|
22
|
+
attr_reader :name
|
23
|
+
# constructs this option with a name. The first character of this is regarded its key, e.g. "Yes" and 'y'.
|
24
|
+
# Unless an option has a proper name (e.g. "Mozart"), do not use the default value of the parameter
|
25
|
+
def initialize(name=self.class.simple_name)
|
26
|
+
@name = name.capitalize
|
27
|
+
@name.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
(other.is_a? Option) && (@name == other.name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_response(r)
|
35
|
+
key == r
|
36
|
+
end
|
37
|
+
|
38
|
+
def as_default
|
39
|
+
"*#{@name} (#{key})*"
|
40
|
+
end
|
41
|
+
|
42
|
+
def as_non_default
|
43
|
+
"#{@name} (#{key})"
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
@name
|
48
|
+
end
|
49
|
+
|
50
|
+
def key
|
51
|
+
@name[0].downcase
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Models an Option that is completely specified by a single letter, e.g. "Y"
|
56
|
+
class SingleLetterOption < Option
|
57
|
+
def as_default
|
58
|
+
key.upcase
|
59
|
+
end
|
60
|
+
|
61
|
+
def as_non_default
|
62
|
+
key
|
63
|
+
end
|
64
|
+
end
|
65
|
+
# The class that identifies a user "Yes". This class is an example of an option where the name of
|
66
|
+
# the option is derived from the name of the class itself. Handy extension.
|
67
|
+
class Yes < SingleLetterOption
|
68
|
+
end
|
69
|
+
|
70
|
+
# The class that identifies a user "No".
|
71
|
+
# @see Yes
|
72
|
+
class No < SingleLetterOption
|
73
|
+
end
|
74
|
+
|
75
|
+
# The class that identifies a user "Cancel".
|
76
|
+
class Cancel < SingleLetterOption
|
77
|
+
end
|
78
|
+
|
79
|
+
# An Option with a name and a positive number used to identify its selection. This is useful when two
|
80
|
+
# Options start with the same character (e.g. "Chai" and "Coffee")
|
81
|
+
class NumberedOption < Option
|
82
|
+
attr_reader :number
|
83
|
+
|
84
|
+
def initialize(number, name)
|
85
|
+
super(name)
|
86
|
+
@number = number
|
87
|
+
end
|
88
|
+
|
89
|
+
# redefine
|
90
|
+
def ==(other)
|
91
|
+
@name == other.name && @number == other.number
|
92
|
+
end
|
93
|
+
|
94
|
+
# redefine
|
95
|
+
def valid_response(r)
|
96
|
+
@number.to_s == r
|
97
|
+
end
|
98
|
+
|
99
|
+
# redefine
|
100
|
+
def as_default
|
101
|
+
"*#{@name} (#{@number})*"
|
102
|
+
end
|
103
|
+
|
104
|
+
# redefine
|
105
|
+
def as_non_default
|
106
|
+
"#{@name} (#{@number})"
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
"#{@name}, #{number}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Singletons
|
115
|
+
YES = Yes.new
|
116
|
+
NO = No.new
|
117
|
+
CANCEL = Cancel.new
|
118
|
+
YN = [YES, NO]
|
119
|
+
YNC = YN + [CANCEL]
|
120
|
+
|
121
|
+
# Models a generic list of options that determines if a particular key results in valid response.
|
122
|
+
# Takes care of generic behavior (display, validity of user response, defaults) when a list of
|
123
|
+
# options is presented to the user.
|
124
|
+
class OptionList
|
125
|
+
DEFAULT_PROMPT = "Do you want to proceed?"
|
126
|
+
|
127
|
+
def initialize(options, default_option_index, prompt, strict, istream=$stdin, ostream=$stdout)
|
128
|
+
# check, list must be non-nil and must have at least two elements
|
129
|
+
@options = options
|
130
|
+
@default_option = options[default_option_index]
|
131
|
+
@prompt = prompt
|
132
|
+
@strict = strict
|
133
|
+
@istream = istream
|
134
|
+
@ostream = ostream
|
135
|
+
end
|
136
|
+
|
137
|
+
def valid_response?(r)
|
138
|
+
@options.each do |option|
|
139
|
+
debug "#{option} == #{@default_option} ? : (#{option == @default_option})"
|
140
|
+
return option if (option == @default_option && r == "") || (option.valid_response(r))
|
141
|
+
end
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
|
145
|
+
# subclasses may override, but don't have to
|
146
|
+
def display_string
|
147
|
+
long_str = ""
|
148
|
+
@options.each_with_index do |option, index|
|
149
|
+
if option == @default_option
|
150
|
+
long_str << option.as_default
|
151
|
+
else
|
152
|
+
long_str << option.as_non_default
|
153
|
+
end
|
154
|
+
long_str << "/" if index < (@options.size-1)
|
155
|
+
end
|
156
|
+
"#{@prompt} [#{long_str}] "
|
157
|
+
end
|
158
|
+
|
159
|
+
# the whole point is subclasses get this for free
|
160
|
+
def show
|
161
|
+
@ostream.print "#{display_string}"
|
162
|
+
response = @istream.gets.chomp!
|
163
|
+
chosen = valid_response? response
|
164
|
+
if @strict
|
165
|
+
until chosen
|
166
|
+
@ostream.print "\nSorry, I don't understand #{response}, #{display_string}"
|
167
|
+
response = @istream.gets.chomp!
|
168
|
+
chosen = valid_response? response
|
169
|
+
end
|
170
|
+
else
|
171
|
+
chosen = @default_option # when not strict, any key => default option
|
172
|
+
end
|
173
|
+
chosen
|
174
|
+
end
|
175
|
+
|
176
|
+
def debug(str)
|
177
|
+
puts "debug: #{str}" if $DEBUG
|
178
|
+
end
|
179
|
+
end
|
180
|
+
# A class that models the simple yes/no interaction with user on command line. Provides several ways to customize.
|
181
|
+
# @example:
|
182
|
+
# ...
|
183
|
+
# Do you want to proceed [Y/n]? y (Enter)
|
184
|
+
# A simple Enter or 'y' returns the YES object. Pressing n returns NO object. Pressing anything else returns a
|
185
|
+
# value that depends on the mode which can be <i>strict</i>. If the mode is strict, it keeps on asking the user till s/he
|
186
|
+
# presses the correct key. If the mode is not strict, any invalid key (other than y, n, or enter) results in whatever
|
187
|
+
# the default option is. Note that the default option is shown as upper case key.
|
188
|
+
# @see CLI#YES
|
189
|
+
# @see #NO
|
190
|
+
class YesNo < OptionList
|
191
|
+
# Creates a YesNo interaction.
|
192
|
+
# @param [Option] default_option the option that should be treated as default. Its default is #YES :-)
|
193
|
+
# @param [String] prompt prompt that should appear. Default is #DEFAULT_PROMPT
|
194
|
+
# @param [Boolean] strict decides if the interaction should demand exact response and loop till user behaves
|
195
|
+
# @param [IO] istream input stream to read user response from
|
196
|
+
# @param [IO] ostream output stream to display output to
|
197
|
+
def initialize(default_option=YES, prompt=DEFAULT_PROMPT, strict=true, istream=$stdin, ostream=$stdout)
|
198
|
+
super(YN, YN.index(default_option), prompt, strict, istream, ostream)
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
class YesNoCancel < OptionList
|
204
|
+
def initialize(default_option=YES, prompt=DEFAULT_PROMPT, strict=true, istream=$stdin, ostream=$stdout)
|
205
|
+
super(YNC, YNC.index(default_option), prompt, strict, istream, ostream)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
# An OptionList where all the Options are NumberedOptions. You can't mix NumberedOptions with others.
|
209
|
+
class NumberedOptions < OptionList
|
210
|
+
# all the options must be NumberedOption instances
|
211
|
+
def initialize(options, default_option_index, prompt, strict, istream=$stdin, ostream=$stdout)
|
212
|
+
super
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
#CLI=LilUtils::CLI
|
219
|
+
#puts CLI::YesNo.new.show
|
220
|
+
#puts CLI::YesNo.new(LilUtils::CLI::NO).show
|
221
|
+
#puts CLI::YesNoCancel.new.show
|
222
|
+
#puts CLI::OptionList.new([CLI::Option.new("Mozart"), CLI::Option.new("Beethoven")], 1, "Pick your pick: ", true).show
|
223
|
+
#one = CLI::NumberedOption.new(1, "Standard")
|
224
|
+
#two = CLI::NumberedOption.new(2, "Expedite")
|
225
|
+
#three = CLI::NumberedOption.new(3, "Special")
|
226
|
+
#puts CLI::NumberedOptions.new([one, two, three], 0, "Select shipping method: ", true).show
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module LilUtils
|
2
|
+
module Misc
|
3
|
+
module Pascal
|
4
|
+
# Returns the nth row of the Pascal's triangle as an array of n+1 elements.
|
5
|
+
# This is an O(n) algorithm. Uses: nCr = nCr-1*(n-r+1)/r which calculates
|
6
|
+
# @param [Integer] n starts at 1
|
7
|
+
# @return [Array] of Integers representing numbers in given row.
|
8
|
+
def self.row(n)
|
9
|
+
raise ArgumentError, "#{n} is not valid" if !n.is_a?(Integer) || n < 1
|
10
|
+
len = n == 1 ? 1 : n + 1
|
11
|
+
a = Array.new(len); a[0] = a[-1] = 1
|
12
|
+
1.upto n/2 do |r|
|
13
|
+
a[r] = a[-r-1] = a[r-1] * (n-r+1)/r
|
14
|
+
r += 1
|
15
|
+
end
|
16
|
+
a
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
#p LilUtils::Misc::Pascal.row(ARGV[0].to_i)
|
data/lib/lilutils.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
require 'lilutils/cli_entry'
|
4
|
+
require 'lilutils/misc_entry'
|
5
|
+
require 'lilutils/algo_test_utils_entry'
|
6
|
+
module Lilutils
|
7
|
+
VERSION = '0.0.1'
|
8
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/lilutils.rb'}"
|
9
|
+
puts "Loading lilutils gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "lilutils/algo_test_utils/data_sets"
|
3
|
+
|
4
|
+
class DataSetsTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
DS = LilUtils::AlgoTestUtils::DataSets
|
7
|
+
|
8
|
+
def test_ascii_strings
|
9
|
+
strs = DS.ascii_strings(100, 5)
|
10
|
+
assert_equal(100, strs.size)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/lilutils'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
class BasicCLITest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
CLI = LilUtils::CLI
|
8
|
+
# Called before every test method runs. Can be used
|
9
|
+
# to set up fixture information.
|
10
|
+
def setup
|
11
|
+
# Do nothing
|
12
|
+
end
|
13
|
+
|
14
|
+
# Called after every test method runs. Can be used to tear
|
15
|
+
# down fixture information.
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
# Do nothing
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_yes_no
|
22
|
+
is = StringIO.open("y\n", "r")
|
23
|
+
os = StringIO.open("", "w")
|
24
|
+
yes = CLI::YesNo.new(CLI::YES, CLI::YesNo::DEFAULT_PROMPT, true, is, os)
|
25
|
+
assert_equal(CLI::YES, yes.show)
|
26
|
+
|
27
|
+
is = StringIO.open("\n", "r") # just enter a newline character
|
28
|
+
no = CLI::YesNo.new(CLI::NO, CLI::YesNo::DEFAULT_PROMPT, true, is, os)
|
29
|
+
assert_equal(CLI::NO, no.show)
|
30
|
+
|
31
|
+
is = StringIO.open("c\n", "r") # invalid character
|
32
|
+
no = CLI::YesNo.new(CLI::NO, CLI::YesNo::DEFAULT_PROMPT, false, is, os) # we must not be strict here
|
33
|
+
assert_equal(CLI::NO, no.show) # default should prevail as 'c' is not recognized
|
34
|
+
|
35
|
+
is = StringIO.open("go away\nz\n\n", "r") # 2 invalid attempts and then a valid attempt to select the default
|
36
|
+
no = CLI::YesNo.new(CLI::NO, CLI::YesNo::DEFAULT_PROMPT, false, is, os) # we must not be strict here
|
37
|
+
assert_equal(CLI::NO, no.show) # default should prevail as we encounter a mere newline
|
38
|
+
is.close
|
39
|
+
os.close
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_yes_no_cancel
|
43
|
+
is = StringIO.open("", "r")
|
44
|
+
os = StringIO.open("", "w")
|
45
|
+
CLI::YNC.each do |option|
|
46
|
+
is = StringIO.open("#{option.key}\n", "r")
|
47
|
+
ync = CLI::YesNoCancel.new(option, "test", true, is, os)
|
48
|
+
assert_equal(option, ync.show)
|
49
|
+
end
|
50
|
+
CLI::YNC.each do |option|
|
51
|
+
is = StringIO.open("\n", "r") # default option matches a mere Enter
|
52
|
+
ync = CLI::YesNoCancel.new(option, "test", true, is, os)
|
53
|
+
assert_equal(option, ync.show)
|
54
|
+
end
|
55
|
+
is.close
|
56
|
+
os.close
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_display_string
|
60
|
+
prompt = "Pick one: "
|
61
|
+
options = []
|
62
|
+
options << CLI::SingleLetterOption.new("Coffee") << CLI::SingleLetterOption.new("Tea") << CLI::SingleLetterOption.new("Milk")
|
63
|
+
# make Tea the default
|
64
|
+
list = CLI::OptionList.new(options, 1, prompt, true)
|
65
|
+
expected = prompt + " [c/T/m] "
|
66
|
+
assert_equal(expected, list.display_string)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_generic_1
|
70
|
+
os = StringIO.open("", "w")
|
71
|
+
cat = CLI::Option.new("cat")
|
72
|
+
dog = CLI::Option.new("dog")
|
73
|
+
elephant = CLI::Option.new("elephant")
|
74
|
+
frog = CLI::Option.new("frog")
|
75
|
+
|
76
|
+
is = StringIO.open("z\ne\n", "r") # choose invalid option and then elephant
|
77
|
+
list = CLI::OptionList.new([cat, dog, elephant, frog], 3, "", true, is, os) # make frog the default
|
78
|
+
assert_equal(elephant, list.show)
|
79
|
+
|
80
|
+
is.close
|
81
|
+
os.close
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_numbers_1
|
85
|
+
os = StringIO.open("", "w")
|
86
|
+
latte = CLI::NumberedOption.new(1, "Latte")
|
87
|
+
mocha = CLI::NumberedOption.new(2, "Mocha")
|
88
|
+
chai = CLI::NumberedOption.new(3, "Chai")
|
89
|
+
machiato = CLI::NumberedOption.new(4, "Caramel Machiato")
|
90
|
+
is = StringIO.open("3\n", "r") # choose Chai
|
91
|
+
list = CLI::NumberedOptions.new([latte, mocha, chai, machiato], 0, "Pick your favorite: ", true, is, os) # make latte the default
|
92
|
+
assert_equal(chai, list.show)
|
93
|
+
|
94
|
+
is.close
|
95
|
+
os.close
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_long_names
|
99
|
+
os = StringIO.open("", "w")
|
100
|
+
|
101
|
+
l = CLI::Option.new("Left Turn")
|
102
|
+
r = CLI::Option.new("Right Turn")
|
103
|
+
u = CLI::Option.new("U Turn")
|
104
|
+
|
105
|
+
is = StringIO.open("u\n", "r") # take a U turn
|
106
|
+
message = "What should I do?"
|
107
|
+
list = CLI::OptionList.new([l, r, u], 1, message, true, is, os)
|
108
|
+
# puts list.display_string
|
109
|
+
assert_equal(u, list.show)
|
110
|
+
|
111
|
+
is = StringIO.open("\n", "r") # right turn as default
|
112
|
+
list = CLI::OptionList.new([l, r, u], 1, message, true, is, os)
|
113
|
+
assert_equal(r, list.show) # enter = right
|
114
|
+
|
115
|
+
is = StringIO.open("r\n", "r") # right turn explicit
|
116
|
+
list = CLI::OptionList.new([l, r, u], 1, message, true, is, os)
|
117
|
+
assert_equal(r, list.show) # right turn selected
|
118
|
+
|
119
|
+
is = StringIO.open("e\nl\n", "r") # invalid and then left
|
120
|
+
list = CLI::OptionList.new([l, r, u], 1, message, true, is, os)
|
121
|
+
assert_equal(l, list.show) # left
|
122
|
+
|
123
|
+
expected_display_string = "#{message} [Left turn (l)/*Right turn (r)*/U turn (u)] "
|
124
|
+
assert_equal(expected_display_string, list.display_string)
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/lilutils'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
class PascalTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
PASCAL = LilUtils::Misc::Pascal
|
8
|
+
# Called before every test method runs. Can be used
|
9
|
+
# to set up fixture information.
|
10
|
+
def setup
|
11
|
+
# Do nothing
|
12
|
+
end
|
13
|
+
|
14
|
+
# Called after every test method runs. Can be used to tear
|
15
|
+
# down fixture information.
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
# Do nothing
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_first_six
|
22
|
+
rows = {1 => [1], 2 => [1, 2, 1], 3 => [1, 3, 3, 1], 4 => [1, 4, 6, 4, 1],
|
23
|
+
5 => [1, 5, 10, 10, 5, 1], 6 => [1, 6, 15, 20, 15, 6, 1]}
|
24
|
+
rows.each_pair do |row_no, row |
|
25
|
+
assert_equal(row, PASCAL.row(row_no))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lilutils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Kedar Mhaswade
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-08 00:00:00 -08:00
|
18
|
+
default_executable: cli-demo
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: shoulda
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
prerelease: false
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 1
|
42
|
+
- 0
|
43
|
+
- 0
|
44
|
+
version: 1.0.0
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: jeweler
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 1
|
57
|
+
- 5
|
58
|
+
- 2
|
59
|
+
version: 1.5.2
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rcov
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
type: :development
|
74
|
+
prerelease: false
|
75
|
+
version_requirements: *id004
|
76
|
+
description: Provides little utilties. It's a gem by a newbie, but I think it is quite useful. As of now, it provides a nicely abstracted out yes/no/cancel dialog box on a console.
|
77
|
+
email: kedar.mhaswade@gmail.com
|
78
|
+
executables:
|
79
|
+
- cli-demo
|
80
|
+
extensions: []
|
81
|
+
|
82
|
+
extra_rdoc_files:
|
83
|
+
- README.rdoc
|
84
|
+
files:
|
85
|
+
- History.txt
|
86
|
+
- Manifest.txt
|
87
|
+
- PostInstall.txt
|
88
|
+
- README.rdoc
|
89
|
+
- Rakefile
|
90
|
+
- bin/cli-demo
|
91
|
+
- lib/lilutils.rb
|
92
|
+
- lib/lilutils/algo_test_utils/data_sets.rb
|
93
|
+
- lib/lilutils/algo_test_utils_entry.rb
|
94
|
+
- lib/lilutils/cli/cli.rb
|
95
|
+
- lib/lilutils/cli_entry.rb
|
96
|
+
- lib/lilutils/misc/misc.rb
|
97
|
+
- lib/lilutils/misc/pascal.rb
|
98
|
+
- lib/lilutils/misc_entry.rb
|
99
|
+
- script/console
|
100
|
+
- script/destroy
|
101
|
+
- script/generate
|
102
|
+
- test/algo_test_utils/data_sets_test.rb
|
103
|
+
- test/cli/cli_basic_test.rb
|
104
|
+
- test/misc/misc_pascal_test.rb
|
105
|
+
- test/test_helper.rb
|
106
|
+
- test/test_lilutils.rb
|
107
|
+
has_rdoc: true
|
108
|
+
homepage: http://github.com/kedarmhaswade/lilutils
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
hash: -896547783063548006
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
segments:
|
131
|
+
- 0
|
132
|
+
version: "0"
|
133
|
+
requirements: []
|
134
|
+
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.3.7
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: Little utilities for everyone
|
140
|
+
test_files:
|
141
|
+
- test/algo_test_utils/data_sets_test.rb
|
142
|
+
- test/cli/cli_basic_test.rb
|
143
|
+
- test/misc/misc_pascal_test.rb
|
144
|
+
- test/test_helper.rb
|
145
|
+
- test/test_lilutils.rb
|