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.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'colorize'
4
+ require 'statsample'
5
+ require 'trollop'
6
+ require 'date_ideas'
7
+ require 'date_idea'
8
+
9
+ $LOAD_PATH.shift
@@ -0,0 +1,3 @@
1
+ module Dates
2
+ VERSION = "1.0.1"
3
+ end
@@ -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: