doodle 0.0.10 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CREDITS +22 -0
- data/{ChangeLog → History.txt} +22 -3
- data/License.txt +20 -0
- data/Manifest.txt +61 -0
- data/README.txt +166 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +77 -0
- data/config/requirements.rb +15 -0
- data/examples/doodle-errors.rb +25 -0
- data/examples/event-location.rb +3 -7
- data/examples/example-01.rb +1 -1
- data/examples/example-01.rdoc +3 -3
- data/examples/example-02.rb +15 -4
- data/examples/example-02.rdoc +17 -5
- data/examples/mail-datatypes.rb +104 -0
- data/examples/mail.rb +85 -0
- data/examples/parent.rb +40 -0
- data/examples/profile-options.rb +67 -0
- data/examples/smtp_tls.rb +65 -0
- data/examples/test-datatypes.rb +55 -0
- data/examples/yaml-example.rb +40 -0
- data/examples/yaml-example2.rb +42 -0
- data/lib/doodle.rb +364 -301
- data/lib/doodle/datatypes.rb +148 -0
- data/lib/doodle/rfc822.rb +31 -0
- data/lib/doodle/utils.rb +13 -0
- data/lib/doodle/version.rb +9 -0
- data/log/debug.log +0 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/spec/arg_order_spec.rb +5 -5
- data/spec/attributes_spec.rb +66 -24
- data/spec/bugs_spec.rb +109 -6
- data/spec/class_spec.rb +7 -4
- data/spec/class_validation_spec.rb +46 -0
- data/spec/class_var_spec.rb +76 -0
- data/spec/collector_spec.rb +16 -30
- data/spec/conversion_spec.rb +8 -3
- data/spec/defaults_spec.rb +4 -4
- data/spec/doodle_context_spec.rb +3 -4
- data/spec/doodle_spec.rb +25 -15
- data/spec/extra_args_spec.rb +1 -1
- data/spec/factory_spec.rb +3 -3
- data/spec/init_spec.rb +11 -11
- data/spec/new_doodle_spec.rb +19 -0
- data/spec/required_spec.rb +1 -1
- data/spec/serialization_spec.rb +3 -6
- data/spec/singleton_spec.rb +5 -5
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/superclass_spec.rb +6 -5
- data/spec/validation2_spec.rb +248 -0
- data/spec/validation_spec.rb +26 -37
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- metadata +76 -20
- data/COPYING +0 -18
- data/README +0 -57
- data/examples/event.rb +0 -39
- data/examples/example-03.rb +0 -45
- data/examples/example-03.rdoc +0 -55
- data/lib/semantic.cache +0 -8
data/examples/example-01.rb
CHANGED
data/examples/example-01.rdoc
CHANGED
@@ -2,7 +2,7 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
2
|
require 'date'
|
3
3
|
require 'doodle'
|
4
4
|
|
5
|
-
class DateRange < Doodle
|
5
|
+
class DateRange < Doodle
|
6
6
|
has :start_date do
|
7
7
|
default { Date.today }
|
8
8
|
end
|
@@ -12,6 +12,6 @@ class DateRange < Doodle::Base
|
|
12
12
|
end
|
13
13
|
|
14
14
|
dr = DateRange.new
|
15
|
-
dr.start_date # => #<Date:
|
16
|
-
dr.end_date # => #<Date:
|
15
|
+
dr.start_date # => #<Date: 4909159/2,0,2299161>
|
16
|
+
dr.end_date # => #<Date: 4909159/2,0,2299161>
|
17
17
|
|
data/examples/example-02.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
require 'date'
|
3
3
|
require 'doodle'
|
4
|
+
require 'doodle/utils' # for try
|
4
5
|
|
5
|
-
class DateRange < Doodle
|
6
|
+
class DateRange < Doodle
|
6
7
|
has :start_date, :kind => Date do
|
7
8
|
default { Date.today }
|
8
9
|
from String do |s|
|
@@ -25,6 +26,8 @@ class DateRange < Doodle::Base
|
|
25
26
|
m = /(\d{4}-\d{2}-\d{2})\s*(?:to|-|\s)\s*(\d{4}-\d{2}-\d{2})/.match(s)
|
26
27
|
if m
|
27
28
|
self.new(*m.captures)
|
29
|
+
else
|
30
|
+
raise Exception, "Cannot parse date: '#{s}'"
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -57,6 +60,14 @@ dr = DateRange.from '2007-01-01 2007-12-31'
|
|
57
60
|
dr.start_date # =>
|
58
61
|
dr.end_date # =>
|
59
62
|
|
60
|
-
|
61
|
-
dr.
|
62
|
-
dr.
|
63
|
+
p try {
|
64
|
+
dr = DateRange.from 'Hello World'
|
65
|
+
dr.start_date # =>
|
66
|
+
dr.end_date # =>
|
67
|
+
}
|
68
|
+
|
69
|
+
p try {
|
70
|
+
dr = DateRange '2008-01-01', '2007-12-31'
|
71
|
+
dr.start_date # =>
|
72
|
+
dr.end_date # =>
|
73
|
+
}
|
data/examples/example-02.rdoc
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
require 'date'
|
3
3
|
require 'doodle'
|
4
|
+
require 'doodle/utils' # for try
|
4
5
|
|
5
|
-
class DateRange < Doodle
|
6
|
+
class DateRange < Doodle
|
6
7
|
has :start_date, :kind => Date do
|
7
8
|
default { Date.today }
|
8
9
|
from String do |s|
|
@@ -25,6 +26,8 @@ class DateRange < Doodle::Base
|
|
25
26
|
m = /(\d{4}-\d{2}-\d{2})\s*(?:to|-|\s)\s*(\d{4}-\d{2}-\d{2})/.match(s)
|
26
27
|
if m
|
27
28
|
self.new(*m.captures)
|
29
|
+
else
|
30
|
+
raise Exception, "Cannot parse date: '#{s}'"
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -57,7 +60,16 @@ dr = DateRange.from '2007-01-01 2007-12-31'
|
|
57
60
|
dr.start_date # => #<Date: 4908203/2,0,2299161>
|
58
61
|
dr.end_date # => #<Date: 4908931/2,0,2299161>
|
59
62
|
|
60
|
-
|
61
|
-
dr.
|
62
|
-
dr.
|
63
|
-
#
|
63
|
+
p try {
|
64
|
+
dr = DateRange.from 'Hello World'
|
65
|
+
dr.start_date # =>
|
66
|
+
dr.end_date # =>
|
67
|
+
}
|
68
|
+
|
69
|
+
p try {
|
70
|
+
dr = DateRange '2008-01-01', '2007-12-31'
|
71
|
+
dr.start_date # =>
|
72
|
+
dr.end_date # =>
|
73
|
+
}
|
74
|
+
# >> #<Doodle::ConversionError: Cannot parse date: 'Hello World'>
|
75
|
+
# >> #<Doodle::ValidationError: DateRange must have end_date >= start_date>
|
@@ -0,0 +1,104 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '.'))
|
3
|
+
|
4
|
+
require 'doodle'
|
5
|
+
require 'doodle/datatypes'
|
6
|
+
require 'net/smtp'
|
7
|
+
require 'time'
|
8
|
+
require 'datatypes'
|
9
|
+
require 'smtp_tls'
|
10
|
+
|
11
|
+
# note: translated from Florian Frank's example in dslkit [http://dslkit.rubyforge.org/]
|
12
|
+
|
13
|
+
class Mail < Doodle
|
14
|
+
doodle do
|
15
|
+
string :mail_server, :default => ENV['MAILSERVER'] || 'mail'
|
16
|
+
string :body
|
17
|
+
email :from do
|
18
|
+
default do
|
19
|
+
if ENV['USER']
|
20
|
+
ENV['USER'] + '@' + mail_server
|
21
|
+
else
|
22
|
+
'from@example.com'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
email :to
|
27
|
+
string :subject, :default => 'Test Email'
|
28
|
+
date :date do
|
29
|
+
default { Time.now.rfc2822 }
|
30
|
+
end
|
31
|
+
string :message_id do
|
32
|
+
default do
|
33
|
+
key = [ ENV['HOSTNAME'] || 'localhost', $$ , Time.now ].join
|
34
|
+
(::Digest::MD5.new << key).to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
string :msg do
|
38
|
+
default do
|
39
|
+
[
|
40
|
+
"From: #{from}",
|
41
|
+
"To: #{to}",
|
42
|
+
"Subject: #{subject}",
|
43
|
+
"Date: #{date}",
|
44
|
+
"Message-Id: <#{message_id}@#{mail_server}>",
|
45
|
+
'',
|
46
|
+
body
|
47
|
+
] * "\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def send_message
|
53
|
+
if true
|
54
|
+
puts msg
|
55
|
+
else
|
56
|
+
::Net::SMTP.start(mail_server, 25) do |smtp|
|
57
|
+
smtp.send_message msg, from, to
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
require 'highline/import'
|
64
|
+
def prompt_for_password
|
65
|
+
ask("Enter your password: ") { |q| q.echo = '*' }
|
66
|
+
end
|
67
|
+
|
68
|
+
class GMail < Mail
|
69
|
+
has :mail_server, :default => 'smtp.gmail.com'
|
70
|
+
has :port, :default => 587
|
71
|
+
has :username, :default => 'sean.ohalpin@gmail.com'
|
72
|
+
has :password, :default => 'sesame'
|
73
|
+
# has :password do
|
74
|
+
# init do
|
75
|
+
# prompt_for_password
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
has :host, :default => 'localhost.localdomain'
|
79
|
+
has :message_format, :default => 'plain'
|
80
|
+
|
81
|
+
def send_message
|
82
|
+
puts msg
|
83
|
+
return
|
84
|
+
::Net::SMTP.start(mail_server,
|
85
|
+
port,
|
86
|
+
host,
|
87
|
+
username,
|
88
|
+
password,
|
89
|
+
message_format) do |smtp|
|
90
|
+
smtp.send_message(msg, from, to)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
GMail do
|
96
|
+
subject subject + ': Hi!'
|
97
|
+
to 'sean.ohalpin@gmail.com'
|
98
|
+
body <<BODY
|
99
|
+
Hi,
|
100
|
+
|
101
|
+
this is a test email from Ruby.
|
102
|
+
|
103
|
+
BODY
|
104
|
+
end.send_message
|
data/examples/mail.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '.'))
|
3
|
+
require 'doodle'
|
4
|
+
require 'doodle/rfc822'
|
5
|
+
require 'net/smtp'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
# note: translated from Florian Frank's example in dslkit [http://dslkit.rubyforge.org/]
|
9
|
+
|
10
|
+
class Mail < Doodle
|
11
|
+
has :mail_server, :default => ENV['MAILSERVER'] || 'mail'
|
12
|
+
has :body, :kind => String
|
13
|
+
|
14
|
+
has :from, :kind => String do
|
15
|
+
default do
|
16
|
+
if ENV['USER']
|
17
|
+
ENV['USER'] + '@' + mail_server
|
18
|
+
else
|
19
|
+
'from@example.com'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
must 'be valid email address' do |s|
|
23
|
+
s =~ RFC822::EmailAddress
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
has :to, :kind => String do
|
28
|
+
must 'be valid email address' do |s|
|
29
|
+
s =~ RFC822::EmailAddress
|
30
|
+
end
|
31
|
+
end
|
32
|
+
has :subject, :default => 'Test Email'
|
33
|
+
has :date do
|
34
|
+
default { Time.now.rfc2822 }
|
35
|
+
end
|
36
|
+
has :message_id do
|
37
|
+
default do
|
38
|
+
key = [ ENV['HOSTNAME'] || 'localhost', $$ , Time.now ].join
|
39
|
+
(::Digest::MD5.new << key).to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
has :msg, :kind => String do
|
43
|
+
default do
|
44
|
+
[
|
45
|
+
"From: #{from}",
|
46
|
+
"To: #{to}",
|
47
|
+
"Subject: #{subject}",
|
48
|
+
"Date: #{date}",
|
49
|
+
"Message-Id: <#{message_id}@#{mail_server}>",
|
50
|
+
'',
|
51
|
+
body
|
52
|
+
] * "\n"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def send
|
57
|
+
if true
|
58
|
+
puts msg
|
59
|
+
else
|
60
|
+
::Net::SMTP.start(mail_server, 25) do |smtp|
|
61
|
+
smtp.send_message msg, from, to
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def mail(&block)
|
68
|
+
Mail.new(&block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def prompt
|
72
|
+
return 'someone@example.com'
|
73
|
+
STDOUT.print "Send to? "
|
74
|
+
STDOUT.flush
|
75
|
+
STDIN.gets.strip
|
76
|
+
end
|
77
|
+
|
78
|
+
m = Mail do
|
79
|
+
subject subject + ': Hi!'
|
80
|
+
if rcpt = prompt
|
81
|
+
to rcpt
|
82
|
+
end
|
83
|
+
body "Hello, world!\n"
|
84
|
+
end
|
85
|
+
m.send
|
data/examples/parent.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'doodle'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class Child < Doodle
|
6
|
+
has :name
|
7
|
+
has :dad do
|
8
|
+
# I'm treating block arguments and Proc object (proc/lambda) arguments
|
9
|
+
# to :init differently:
|
10
|
+
# - a proc/lamba is treated as a literal argument, i.e. the
|
11
|
+
# - value is set to a Proc
|
12
|
+
# - a block argument, on the other hand, is instance
|
13
|
+
# - evaluated during initialization
|
14
|
+
# - consequences
|
15
|
+
# - can only be done in init block
|
16
|
+
# - somewhat subtle difference (from programmer's point of
|
17
|
+
# - view) between a proc and a block
|
18
|
+
|
19
|
+
# Also note re: Doodle.parent - its value is only valid
|
20
|
+
# during initialization - this is a way to capture that
|
21
|
+
# value for ues later
|
22
|
+
|
23
|
+
init do
|
24
|
+
parent
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Parent < Child
|
30
|
+
has :children, :collect => Child
|
31
|
+
end
|
32
|
+
|
33
|
+
parent = Parent 'Conn' do
|
34
|
+
child 'Sean'
|
35
|
+
end
|
36
|
+
|
37
|
+
puts parent.to_yaml
|
38
|
+
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'lib/doodle'
|
2
|
+
|
3
|
+
module CommandLine
|
4
|
+
class Base < Doodle::Base
|
5
|
+
has :name
|
6
|
+
singleton_class do
|
7
|
+
has :doc
|
8
|
+
end
|
9
|
+
def to_s
|
10
|
+
name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class Command < Base
|
14
|
+
end
|
15
|
+
class KeyValue < Base
|
16
|
+
# specify order (should I need to do this?)
|
17
|
+
has :name
|
18
|
+
has :value
|
19
|
+
def to_s
|
20
|
+
%[--#{name}="#{value}"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
class Flag < Base
|
24
|
+
def to_s
|
25
|
+
%[--#{name}]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Zenity
|
31
|
+
include CommandLine
|
32
|
+
class Entry < Flag
|
33
|
+
# specifying name here has effect of re-ordering positional args
|
34
|
+
doc "Display text entry dialogue"
|
35
|
+
has :name, :default => :entry
|
36
|
+
end
|
37
|
+
class Text < KeyValue
|
38
|
+
doc "Set the dialogue text"
|
39
|
+
has :name, :default => :text
|
40
|
+
end
|
41
|
+
class EntryText < KeyValue
|
42
|
+
doc "Set the entry text"
|
43
|
+
has :name, :default => 'entry-text'
|
44
|
+
end
|
45
|
+
class HideText < KeyValue
|
46
|
+
doc "Hide the entry text"
|
47
|
+
has :name, :default => 'hide-text'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
include Zenity
|
52
|
+
|
53
|
+
1.upto(100) do
|
54
|
+
cmd = [
|
55
|
+
Command.new("zenity"),
|
56
|
+
Entry.new(),
|
57
|
+
# KeyValue.new("text", "Enter name:"),
|
58
|
+
# KeyValue.new(:name => "text", :value => "Enter name:"),
|
59
|
+
# Text.new(:value => "Enter name:"),
|
60
|
+
Text.new(:value => "Enter name:"),
|
61
|
+
EntryText.new(:value => "Enter text"),
|
62
|
+
].join(' ')
|
63
|
+
#puts cmd
|
64
|
+
end
|
65
|
+
#result = `#{cmd}`
|
66
|
+
#puts "result=#{result}"
|
67
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "openssl"
|
2
|
+
require "net/smtp"
|
3
|
+
|
4
|
+
Net::SMTP.class_eval do
|
5
|
+
private
|
6
|
+
def do_start(helodomain, user, secret, authtype)
|
7
|
+
raise IOError, 'SMTP session already started' if @started
|
8
|
+
check_auth_args user, secret, authtype if user or secret
|
9
|
+
|
10
|
+
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
|
11
|
+
@socket = Net::InternetMessageIO.new(sock)
|
12
|
+
@socket.read_timeout = 60 #@read_timeout
|
13
|
+
|
14
|
+
check_response(critical { recv_response() })
|
15
|
+
do_helo(helodomain)
|
16
|
+
|
17
|
+
if starttls
|
18
|
+
raise 'openssl library not installed' unless defined?(OpenSSL)
|
19
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock)
|
20
|
+
ssl.sync_close = true
|
21
|
+
ssl.connect
|
22
|
+
@socket = Net::InternetMessageIO.new(ssl)
|
23
|
+
@socket.read_timeout = 60 #@read_timeout
|
24
|
+
do_helo(helodomain)
|
25
|
+
end
|
26
|
+
|
27
|
+
authenticate user, secret, authtype if user
|
28
|
+
@started = true
|
29
|
+
ensure
|
30
|
+
unless @started
|
31
|
+
# authentication failed, cancel connection.
|
32
|
+
@socket.close if not @started and @socket and not @socket.closed?
|
33
|
+
@socket = nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_helo(helodomain)
|
38
|
+
begin
|
39
|
+
if @esmtp
|
40
|
+
ehlo helodomain
|
41
|
+
else
|
42
|
+
helo helodomain
|
43
|
+
end
|
44
|
+
rescue Net::ProtocolError
|
45
|
+
if @esmtp
|
46
|
+
@esmtp = false
|
47
|
+
@error_occured = false
|
48
|
+
retry
|
49
|
+
end
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def starttls
|
55
|
+
getok('STARTTLS') rescue return false
|
56
|
+
return true
|
57
|
+
end
|
58
|
+
|
59
|
+
def quit
|
60
|
+
begin
|
61
|
+
getok('QUIT')
|
62
|
+
rescue EOFError
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|