shellout 0.4 → 0.5

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.
@@ -0,0 +1,50 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'shellout/query'
3
+ require 'shellout/date'
4
+
5
+ module Shellout
6
+ class DateQuery < Query
7
+
8
+ def initialize
9
+ super("Date (?)", "today")
10
+ end
11
+
12
+ def call
13
+ loop do
14
+ date = super
15
+ return date if date
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def ask
22
+ answer = super
23
+ if answer == '?'
24
+ print_help
25
+ return
26
+ end
27
+ parse(answer)
28
+ end
29
+
30
+ def parse(answer)
31
+ Shellout::Date.from_str(answer)
32
+ rescue => e
33
+ puts e.message
34
+ end
35
+
36
+ def print_help
37
+ puts <<'EOT'
38
+ Accepted input formats:
39
+ today - today
40
+ [+|-]N - ±N days from today
41
+ D?D - FIXME
42
+ M?M-D?D - FIXME
43
+ (YY)?YY-M?M-D?D - FIXME
44
+
45
+ EOT
46
+ Shellout::Calendar.new.print3
47
+ end
48
+
49
+ end
50
+ end
@@ -1,8 +1,9 @@
1
1
  module Shellout
2
2
  class Menu
3
3
 
4
- def initialize(items)
5
- @items = items
4
+ def initialize(items, zero_item=nil)
5
+ @items = items
6
+ @zero_item = zero_item
6
7
  end
7
8
 
8
9
  def padding; 1; end
@@ -12,6 +13,7 @@ module Shellout
12
13
  @items.each_with_index do |item, i|
13
14
  out.printf format, i+1, item
14
15
  end
16
+ out.printf format, 0, @zero_item unless @zero_item.nil?
15
17
  end
16
18
 
17
19
  private
@@ -0,0 +1,51 @@
1
+ require 'shellout/query'
2
+ require 'shellout'
3
+
4
+ module Shellout
5
+ class MenuQuery
6
+
7
+ include Shellout
8
+
9
+ def initialize(items, last_is_the_zero_item=false)
10
+ @items = items.is_a?(Array) ? Hash[*(items.zip(items).flatten)] : items
11
+ @has_a_zero_item = last_is_the_zero_item
12
+ initialize_menu
13
+ @prompt_class = Query
14
+ end
15
+
16
+ def call
17
+ loop do
18
+ @menu.print
19
+ answer = ask
20
+ return answer if answer
21
+ puts "Invalid user input!"
22
+ end
23
+ end
24
+
25
+ def prompt_class=(klass)
26
+ @prompt_class = klass
27
+ end
28
+
29
+ def ask
30
+ return @items.values[0] if only_one_option?
31
+ answer = @prompt_class.new('', 1).call.to_i
32
+ return nil if answer < 0
33
+ return nil if answer == 0 and !@has_a_zero_item
34
+ index = (@has_a_zero_item and answer == "0") ? -1 : answer.to_i-1
35
+ @items.values[index]
36
+ end
37
+
38
+ private
39
+
40
+ def initialize_menu
41
+ menu_items = @items.keys
42
+ zero_item = @has_a_zero_item ? menu_items.pop : nil
43
+ @menu = Menu(menu_items, zero_item)
44
+ end
45
+
46
+ def only_one_option?
47
+ @items.length == 1 && !@has_a_zero_item
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ module Shellout
2
+ class Paragraph
3
+
4
+ def initialize(str)
5
+ @str = str
6
+ @padding = 0
7
+ @width = 80
8
+ end
9
+
10
+ def width(width)
11
+ @width = width
12
+ self
13
+ end
14
+
15
+ def padding(width)
16
+ @padding = width
17
+ self
18
+ end
19
+
20
+ def print(out=$stdout)
21
+ text_width = @width - @padding
22
+ text = ' '*@padding + @str
23
+ # Stolen from ActionView::Helpers::TextHelper#word_wrap
24
+ p = text.split("\n").collect do |line|
25
+ line.length > text_width ? line.gsub(/(.{1,#{text_width}})(\s+|$)/, "\\1\n" + ' '*@padding).rstrip : line
26
+ end * "\n"
27
+ out.puts p
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'readline'
2
+
3
+ module Shellout
4
+ class Query
5
+
6
+ def initialize(question='', default=nil)
7
+ @question = question + (default.nil? ? '' : " [#{default}]")
8
+ @default = default
9
+ @io = Readline
10
+ end
11
+
12
+ def io=(io)
13
+ @io = io
14
+ end
15
+
16
+ def call
17
+ answer = ask
18
+ return answer == '' ? @default : answer
19
+ end
20
+
21
+ private
22
+
23
+ def bold(text); "\e[1m#{text}\e[0m"; end
24
+
25
+ def ask
26
+ answer = @io.readline(bold("#{@question}> "), true)
27
+ answer.strip
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ module Shellout
2
+ class Task
3
+
4
+ # For executing sub tasks in correct order, we depend on the fact that
5
+ # hash iteration is in insert order
6
+
7
+ def initialize
8
+ @sub_tasks = {}
9
+ @on_call_done = ->{}
10
+ yield self if block_given?
11
+ end
12
+
13
+ def method_missing(name, *args)
14
+ super unless name =~ /=$/
15
+ add_sub_task(name.to_s.chop, args.first)
16
+ end
17
+
18
+ def add_sub_task(name, sub)
19
+ @sub_tasks[name.to_sym] = sub
20
+ end
21
+
22
+ def printf(format)
23
+ @sub_tasks['printf'] = -> do
24
+ super(format, @results)
25
+ end
26
+ end
27
+
28
+ def on_call_done(&callback)
29
+ @on_call_done = callback
30
+ end
31
+
32
+ def call
33
+ @results = {}
34
+ @sub_tasks.each do |k, sub|
35
+ @results[k] = sub.call
36
+ end
37
+ @on_call_done.call
38
+ end
39
+
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Shellout
2
- VERSION = '0.4'
2
+ VERSION = '0.5'
3
3
  end
@@ -16,9 +16,12 @@ Gem::Specification.new do |s|
16
16
  s.test_files = `git ls-files -- spec/*`.split("\n")
17
17
  s.require_paths = ["lib"]
18
18
 
19
- s.add_development_dependency "rspec"
20
- s.add_development_dependency "guard"
21
- s.add_development_dependency "guard-rspec"
19
+ s.add_development_dependency "rspec", '2.14.1'
20
+ s.add_development_dependency "guard", '1.8.2'
21
+ s.add_development_dependency "guard-rspec", '3.0.2'
22
+ s.add_development_dependency "rake", '10.1.0'
23
+ s.add_development_dependency "cucumber", '1.3.10'
24
+ s.add_development_dependency "aruba", '0.5.3'
22
25
 
23
26
  if RUBY_PLATFORM.downcase.include?("darwin")
24
27
  s.add_development_dependency 'rb-fsevent'
@@ -45,6 +45,35 @@ Mo Tu We Th Fr Sa Su
45
45
  17 18 19 20 21 22 23
46
46
  24 25 26 27 28 29 \e[7m30\e[0m
47
47
  31
48
+ EOC
49
+ end
50
+
51
+ it 'should highlight todays date if calendar is todays month' do
52
+ Calendar().print(@out)
53
+ res = @out.string.gsub(/\s+\n/, "\n")
54
+ res.should == <<EOC
55
+ October 2011
56
+ Mo Tu We Th Fr Sa Su
57
+ 1 2
58
+ 3 4 5 6 7 8 9
59
+ 10 11 12 13 14 15 16
60
+ 17 18 19 20 21 22 23
61
+ 24 25 26 27 28 29 \e[7m30\e[0m
62
+ 31
63
+ EOC
64
+ end
65
+
66
+ it 'should not highlight todays date if calendar is todays month, but not the same year' do
67
+ Calendar(Date.new(2012, 10, 30)).print(@out)
68
+ res = @out.string.gsub(/\s+\n/, "\n")
69
+ res.should == <<EOC
70
+ October 2012
71
+ Mo Tu We Th Fr Sa Su
72
+ 1 2 3 4 5 6 7
73
+ 8 9 10 11 12 13 14
74
+ 15 16 17 18 19 20 21
75
+ 22 23 24 25 26 27 28
76
+ 29 30 31
48
77
  EOC
49
78
  end
50
79
 
@@ -79,4 +108,4 @@ Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
79
108
  EOC
80
109
  end
81
110
  end
82
- end
111
+ end
@@ -0,0 +1,9 @@
1
+ require 'shellout/command_loop'
2
+
3
+ module Shellout
4
+ describe CommandLoop do
5
+
6
+ # It compiles!
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'shellout/date_query'
2
+
3
+ module Shellout
4
+ describe DateQuery do
5
+
6
+ # It compiles!
7
+
8
+ end
9
+ end
@@ -0,0 +1,87 @@
1
+ require 'shellout/date'
2
+
3
+ module Shellout
4
+ describe Date do
5
+
6
+ describe "#from_str" do
7
+
8
+ before(:each) do
9
+ @today = Date.today
10
+ end
11
+
12
+
13
+ context "when English date string is given" do
14
+ it "should parse 'today'" do
15
+ Date.from_str("today").should == @today
16
+ end
17
+
18
+ it "should parse '' as 'today'" do
19
+ Date.from_str("").should == @today
20
+ end
21
+ end
22
+
23
+
24
+ context "when an offset is given" do
25
+ it "should parse '+1' as tomorrow" do
26
+ Date.from_str("+1").should == @today+1
27
+ end
28
+
29
+ it "should parse '-1' as yesterday" do
30
+ Date.from_str("-1").should == @today-1
31
+ end
32
+ end
33
+
34
+
35
+ context "when only the day of month is given" do
36
+ it "should parse '1'" do
37
+ Date.from_str("1").should == Date.civil(@today.year, @today.month, 1)
38
+ end
39
+
40
+ it "should parse '20'" do
41
+ Date.from_str("20").should == Date.civil(@today.year, @today.month, 20)
42
+ end
43
+ end
44
+
45
+
46
+ context "when the month and day of month are given" do
47
+ it "should parse '11-1'" do
48
+ Date.from_str("11-1").should == Date.civil(@today.year, 11, 1)
49
+ end
50
+
51
+ it "should parse '11-01'" do
52
+ Date.from_str("11-01").should == Date.civil(@today.year, 11, 1)
53
+ end
54
+ end
55
+
56
+ context "when year, month, and day of month are given" do
57
+
58
+ # Two digits in year
59
+ it "should parse '11-11-11' as 2011-11-11" do
60
+ Date.from_str("11-11-11").should == Date.civil(2011, 11, 11)
61
+ end
62
+
63
+ it "should parse '91-11-11' as 1991-11-11" do
64
+ Date.from_str("91-11-11").should == Date.civil(1991, 11, 11)
65
+ end
66
+
67
+ # > Two digits in year
68
+ it "should parse '111-11-1' as 111-11-1" do
69
+ Date.from_str("111-11-1").should == Date.civil(111, 11, 1)
70
+ end
71
+
72
+ it "should parse '2008-08-26' as 2008-08-26" do
73
+ Date.from_str("2008-08-26").should == Date.civil(2008, 8, 26)
74
+ end
75
+ end
76
+
77
+ it "should fail on nil" do
78
+ expect { Date.from_str(nil) }.to raise_error(ArgumentError)
79
+ end
80
+
81
+ it "should fail on strings containing junk" do
82
+ expect { Date.from_str("foobar") }.to raise_error(ArgumentError)
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,39 @@
1
+ require 'shellout/menu_query'
2
+
3
+ module Shellout
4
+ describe MenuQuery do
5
+
6
+ describe "#ask" do
7
+ before :each do
8
+ @query = MenuQuery.new(%w(a b c))
9
+ end
10
+
11
+ def make_prompt_return(value)
12
+ prompt = double('prompt')
13
+ prompt.stub_chain(:new, :call).and_return(value)
14
+ @query.prompt_class = prompt
15
+ end
16
+
17
+ it "should return first element when prompt query returns '1'" do
18
+ make_prompt_return('1')
19
+ @query.ask.should == 'a'
20
+ end
21
+
22
+ it "should return second element when prompt query returns '2'" do
23
+ make_prompt_return('2')
24
+ @query.ask.should == 'b'
25
+ end
26
+
27
+ it "should return nil if user answer is invalid (too large)" do
28
+ make_prompt_return('9')
29
+ @query.ask.should == nil
30
+ end
31
+
32
+ it "should return nil if user answer is invalid (0)" do
33
+ make_prompt_return('0')
34
+ @query.ask.should == nil
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -1,31 +1,32 @@
1
1
  require 'stringio'
2
2
  require 'shellout'
3
3
 
4
- describe Shellout::Menu do
4
+ module Shellout
5
+ describe Menu do
5
6
 
6
- include Shellout
7
+ include Shellout
7
8
 
8
- before(:each) do
9
- @out = StringIO.new
10
- end
9
+ before(:each) do
10
+ @out = StringIO.new
11
+ end
11
12
 
12
- it "should work for a basic example" do
13
- Menu(%w(a b c)).print(@out)
14
- @out.string.should == <<EOT
13
+ it "should work for a basic example" do
14
+ Menu(%w(a b c)).print(@out)
15
+ @out.string.should == <<EOT
15
16
  1. a
16
17
  2. b
17
18
  3. c
18
19
  EOT
19
- end
20
+ end
20
21
 
21
- it "should print nothing when no items are given" do
22
- Menu([]).print(@out)
23
- @out.string.should == ''
24
- end
22
+ it "should print nothing when no items are given" do
23
+ Menu([]).print(@out)
24
+ @out.string.should == ''
25
+ end
25
26
 
26
- it "should right justify the menu item number" do
27
- Menu(('a'..'j').to_a).print(@out)
28
- @out.string.should == <<EOT
27
+ it "should right justify the menu item number" do
28
+ Menu(('a'..'j').to_a).print(@out)
29
+ @out.string.should == <<EOT
29
30
  1. a
30
31
  2. b
31
32
  3. c
@@ -37,7 +38,17 @@ EOT
37
38
  9. i
38
39
  10. j
39
40
  EOT
40
- end
41
+ end
41
42
 
42
-
43
+ it "should put the zero item last, prefixed by a '0.'" do
44
+ Menu(%w(a b c), 'd').print(@out)
45
+ @out.string.should == <<EOT
46
+ 1. a
47
+ 2. b
48
+ 3. c
49
+ 0. d
50
+ EOT
51
+ end
52
+
53
+ end
43
54
  end