dates 1.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/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:
|