dates 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +46 -0
- data/bin/dates +61 -0
- data/lib/date_idea.rb +70 -0
- data/lib/date_ideas.rb +96 -0
- data/lib/dates.rb +9 -0
- data/lib/version.rb +3 -0
- data/test/spec.rb +76 -0
- metadata +87 -0
data/README.mdown
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
Dates keeps track of things you two have been meaning to do, and learns what's been fun and what hasn't along several different dimensions (adventure, romantic, intellectual, athletic).
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
$ bundle exec bin/dates.rb --help
|
6
|
+
dates 1.0.0-beta, max & daphne.
|
7
|
+
Usage: dates.rb [command] [options] <ideas-file>
|
8
|
+
|
9
|
+
To see help for a specific command, use the --help switch on that command.
|
10
|
+
|
11
|
+
Commands:
|
12
|
+
choose Choose a good date idea for right now! [default command]
|
13
|
+
list Parse and list the contents of the date ideas file.
|
14
|
+
|
15
|
+
Global options:
|
16
|
+
--version, -v: Print version and exit
|
17
|
+
--help, -h: Show this message
|
18
|
+
|
19
|
+
To run it, the simplest way is just to provide it with an ideas file and nothing else:
|
20
|
+
|
21
|
+
$ bundle exec bin/dates.rb ideas.rb
|
22
|
+
watch _serenity_: (intellectual: 5, athletic: 0, adventure: 2, romantic: 4)
|
23
|
+
|
24
|
+
### Commands
|
25
|
+
|
26
|
+
The `choose` command picks a date, and it takes two options:
|
27
|
+
|
28
|
+
$ bundle exec bin/dates.rb choose --help
|
29
|
+
dates 1.0.0-beta, max & daphne.
|
30
|
+
Options for `choose` command:
|
31
|
+
--weather, -w <f>: Current weather score [0-9] (default: 5.0)
|
32
|
+
--time, -t <f>: Time commitment score [0-9] (default: 5.0)
|
33
|
+
|
34
|
+
The `list` command prints out the contents of an ideas file:
|
35
|
+
|
36
|
+
$ bundle exec bin/dates.rb list --help
|
37
|
+
dates 1.0.0-beta, max & daphne.
|
38
|
+
Options for `list` command:
|
39
|
+
--incomplete, -i: Only the incomplete dates
|
40
|
+
--complete, -c: Only the completed dates (with feedback)
|
41
|
+
|
42
|
+
## Tests
|
43
|
+
|
44
|
+
Dates uses RSpec 2 (core and expectations) for tests. To run them, just call:
|
45
|
+
|
46
|
+
bundle exec rspec test/spec.rb -c -f d
|
data/bin/dates
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/dates'
|
4
|
+
|
5
|
+
SUB_COMMANDS = %w(list choose)
|
6
|
+
VERSION_STR = "dates 1.0.0-beta, max & daphne."
|
7
|
+
global_opts = Trollop::options do
|
8
|
+
version VERSION_STR
|
9
|
+
banner <<-EOS
|
10
|
+
#{VERSION_STR}
|
11
|
+
Usage: dates.rb [command] [options] <ideas-file>
|
12
|
+
|
13
|
+
To see help for a specific command, use the --help switch on that command.
|
14
|
+
|
15
|
+
Commands:
|
16
|
+
choose Choose a good date idea for right now! [default command]
|
17
|
+
list Parse and list the contents of the date ideas file.
|
18
|
+
|
19
|
+
Global options:
|
20
|
+
EOS
|
21
|
+
|
22
|
+
stop_on SUB_COMMANDS
|
23
|
+
end
|
24
|
+
|
25
|
+
cmd = ARGV.shift if ARGV.length > 1
|
26
|
+
|
27
|
+
cmd_opts = case cmd
|
28
|
+
when "list"
|
29
|
+
Trollop::options do
|
30
|
+
version VERSION_STR
|
31
|
+
banner "#{VERSION_STR}\nOptions for `list` command:"
|
32
|
+
opt :incomplete, "Only the incomplete dates", :short => :i
|
33
|
+
opt :complete, "Only the completed dates (with feedback)", :short => :c
|
34
|
+
end
|
35
|
+
else # `choose` is default command: can be called without explicit specification
|
36
|
+
Trollop::options do
|
37
|
+
version VERSION_STR
|
38
|
+
banner "#{VERSION_STR}\nOptions for `choose` command:"
|
39
|
+
opt :weather, "Current weather score [0-9]", :short => :w, :default => 5.0
|
40
|
+
opt :time, "Time commitment score [0-9]", :short => :t, :default => 5.0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if ARGV.length < 1
|
45
|
+
Trollop::die "Ideas file required"
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
ideas = eval(File.read(ARGV.first))
|
50
|
+
|
51
|
+
if "list" == cmd
|
52
|
+
if cmd_opts[:complete] and cmd_opts[:incomplete]
|
53
|
+
Trollop::die "-i and -c are mutually exclusive options for `list`"
|
54
|
+
else
|
55
|
+
puts ideas.list(cmd_opts)
|
56
|
+
end
|
57
|
+
elsif "choose" == cmd
|
58
|
+
puts ideas.choose(cmd_opts[:weather], cmd_opts[:time])
|
59
|
+
else
|
60
|
+
puts ideas.choose(cmd_opts[:weather], cmd_opts[:time])
|
61
|
+
end
|
data/lib/date_idea.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
class DateIdea
|
2
|
+
|
3
|
+
def initialize(name = "")
|
4
|
+
@name = name.to_s
|
5
|
+
@attributes = {}
|
6
|
+
@requirements = {}
|
7
|
+
@outcome = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def kind(args)
|
11
|
+
args.each do |field, value|
|
12
|
+
@attributes[field] = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def requires(args)
|
17
|
+
args.each do |field, value|
|
18
|
+
@requirements[field] = value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def outcome(score = nil)
|
23
|
+
if score.nil?
|
24
|
+
@outcome
|
25
|
+
else
|
26
|
+
@outcome = score
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def outcome_safe
|
31
|
+
return @outcome unless @outcome.nil?
|
32
|
+
-1
|
33
|
+
end
|
34
|
+
|
35
|
+
def attributes
|
36
|
+
@attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
def attribute(name)
|
40
|
+
@attributes[name]
|
41
|
+
end
|
42
|
+
|
43
|
+
def requirements
|
44
|
+
@requirements
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
@name
|
49
|
+
end
|
50
|
+
|
51
|
+
def score
|
52
|
+
@outcome
|
53
|
+
end
|
54
|
+
|
55
|
+
def stub?
|
56
|
+
@attributes.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def complete?
|
60
|
+
not @outcome.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
attr_str = @attributes.map { |k,v| "#{k}: #{v}" }.join(", ")
|
65
|
+
date_str = "#{@name}: (#{attr_str})"
|
66
|
+
date_str = date_str + ", outcome: #{@outcome}" unless @outcome.nil?
|
67
|
+
"#{date_str}\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/date_ideas.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
class DateIdeas
|
2
|
+
|
3
|
+
ATTRIBUTES = %w(adventure romantic athletic intellectual)
|
4
|
+
|
5
|
+
def initialize(&block)
|
6
|
+
@date_ideas = []
|
7
|
+
instance_eval &block
|
8
|
+
end
|
9
|
+
|
10
|
+
def ideas
|
11
|
+
@date_ideas
|
12
|
+
end
|
13
|
+
|
14
|
+
def date(name, &block)
|
15
|
+
date = DateIdea.new(name)
|
16
|
+
if block
|
17
|
+
date.instance_eval(&block)
|
18
|
+
end
|
19
|
+
@date_ideas << date
|
20
|
+
end
|
21
|
+
|
22
|
+
def list(opts)
|
23
|
+
if opts[:complete]
|
24
|
+
render complete
|
25
|
+
elsif opts[:incomplete]
|
26
|
+
render incomplete
|
27
|
+
else
|
28
|
+
render
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def render(ideas = nil)
|
33
|
+
if nil == ideas
|
34
|
+
ideas = @date_ideas
|
35
|
+
end
|
36
|
+
str = "Date ideas:\n"
|
37
|
+
ideas.each do |f|
|
38
|
+
if not f.complete?
|
39
|
+
str << " #{f.to_s}".blue
|
40
|
+
elsif f.complete? and f.score >= 6.0
|
41
|
+
str << " #{f.to_s}".green
|
42
|
+
elsif f.complete? and f.score < 6.0
|
43
|
+
str << " #{f.to_s}".red
|
44
|
+
else
|
45
|
+
raise Exception("We should never reach this.")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
str
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
render
|
53
|
+
end
|
54
|
+
|
55
|
+
def complete
|
56
|
+
@date_ideas.reject { |idea| idea.stub? or not idea.complete? }
|
57
|
+
end
|
58
|
+
|
59
|
+
def incomplete
|
60
|
+
@date_ideas.reject { |idea| idea.stub? or idea.complete? }
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_features(idea_list)
|
64
|
+
keys = idea_list.reduce([]) { |acc, idea|
|
65
|
+
acc << idea.attributes.keys
|
66
|
+
}.flatten.uniq
|
67
|
+
features = idea_list.map { |idea|
|
68
|
+
attributes = idea.attributes.map { |key, val|
|
69
|
+
[keys.index(key), val]
|
70
|
+
}.sort_by {|k| k[0]}.map { |e| e[1] }
|
71
|
+
[attributes, idea.outcome_safe]
|
72
|
+
}
|
73
|
+
[keys, features]
|
74
|
+
end
|
75
|
+
|
76
|
+
def fitted_model
|
77
|
+
dimensions, examples = complete_features
|
78
|
+
terms = examples.map { |examples|
|
79
|
+
examples[0] + examples[0].permutation(2).to_a.map { |term| term.reduce(1) {|acc,k| acc*k } }
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def complete_features
|
84
|
+
extract_features(complete)
|
85
|
+
end
|
86
|
+
|
87
|
+
def incomplete_features
|
88
|
+
extract_features(incomplete)
|
89
|
+
end
|
90
|
+
|
91
|
+
def choose(weather, time)
|
92
|
+
fitted_model
|
93
|
+
incomplete.first
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/lib/dates.rb
ADDED
data/lib/version.rb
ADDED
data/test/spec.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__)+ '/../lib/dates'
|
2
|
+
|
3
|
+
ideas = DateIdeas.new do
|
4
|
+
|
5
|
+
date "watch primer in north" do
|
6
|
+
kind :adventure => 2, :romantic => 4, :intellectual => 6, :athletic => 0
|
7
|
+
requires :weather => 0, :hours => 2
|
8
|
+
outcome 20
|
9
|
+
end
|
10
|
+
|
11
|
+
date "very close to primer" do
|
12
|
+
kind :adventure => 2, :romantic => 4, :intellectual => 6, :athletic => 1
|
13
|
+
requires :weather => 0, :hours => 2
|
14
|
+
end
|
15
|
+
|
16
|
+
date "very far from primer" do
|
17
|
+
kind :adventure => 10, :romantic => 10, :intellectual => 0, :athletic => 10
|
18
|
+
requires :weather => 0, :hours => 2
|
19
|
+
end
|
20
|
+
|
21
|
+
date "escher in the DiVE" do
|
22
|
+
kind :adventure => 4, :romantic => 3, :intellectual => 4, :athletic => 0
|
23
|
+
requires :weather => 0, :hours => 2
|
24
|
+
end
|
25
|
+
|
26
|
+
date "mushroom hunting" do
|
27
|
+
kind :adventure => 6, :romantic => 3, :intellectual => 5, :athletic => 3
|
28
|
+
requires :weather => 5, :hours => 2
|
29
|
+
end
|
30
|
+
|
31
|
+
date "duke observatory" do
|
32
|
+
kind :adventure => 100, :romantic => 7, :intellectual => 5, :athletic => 1
|
33
|
+
requires :weather => 8, :hours => 4
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
valid_attributes = [:adventure, :romantic, :intellectual, :athletic]
|
39
|
+
|
40
|
+
describe Date do
|
41
|
+
|
42
|
+
describe "interprets an ideas file" do
|
43
|
+
it "correctly identifies incomplete and completed dates" do
|
44
|
+
ideas.incomplete.length.should == 5
|
45
|
+
ideas.complete.length.should == 1
|
46
|
+
ideas.complete.first.name == "watch primer in north"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "correctly loads the attributes and requirements for each date" do
|
50
|
+
ideas.ideas.map { |idea|
|
51
|
+
if idea.stub?
|
52
|
+
idea.attributes.empty?.should == true
|
53
|
+
else
|
54
|
+
idea.attributes.length.should == valid_attributes.length
|
55
|
+
idea.attributes.map { |name, val|
|
56
|
+
valid_attributes.member?(name).should == true
|
57
|
+
}
|
58
|
+
end
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "list command" do
|
64
|
+
it "lists the contents of a dates file correctly" do
|
65
|
+
ideas.ideas.length.should == 6
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "choose command" do
|
70
|
+
it "chooses a date from the incomplete dates list" do
|
71
|
+
choosed = ideas.choose(2, 2)
|
72
|
+
ideas.incomplete.member?(choosed).should == true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dates
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Max Hodak, Daphne Ezer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-15 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: statsample
|
16
|
+
requirement: &70326830794380 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70326830794380
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: colorize
|
27
|
+
requirement: &70326830793940 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70326830793940
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: trollop
|
38
|
+
requirement: &70326830793520 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70326830793520
|
47
|
+
description: Dates keeps track of things you two have been meaning to do, and learns
|
48
|
+
to make good suggestions as you teach it.
|
49
|
+
email: maxhodak@gmail.com
|
50
|
+
executables:
|
51
|
+
- dates
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- README.mdown
|
56
|
+
- bin/dates
|
57
|
+
- lib/date_idea.rb
|
58
|
+
- lib/date_ideas.rb
|
59
|
+
- lib/dates.rb
|
60
|
+
- lib/version.rb
|
61
|
+
- test/spec.rb
|
62
|
+
homepage: http://www.github.com/maxhodak/dates
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.6
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Dates keeps track of things you two have been meaning to do.
|
86
|
+
test_files: []
|
87
|
+
has_rdoc:
|