winston 0.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b136df3119babb39b3950a0cc96b393d3344453e
4
+ data.tar.gz: c10c1db2ceda4d4a553b209e7fceb433375eeabd
5
+ SHA512:
6
+ metadata.gz: d47e3a5f91c608f5c5ad49a649bc9aabf9fd29a243ce0efffa89610a2ba1ad37c68ea026cefbf0b42a1fd0574887af20a50820bd357a0c85f5bd8fe5670ea0a9
7
+ data.tar.gz: f4a9e5f2c31ef671a50618eb0236d15f59861cf39c2659c980dc34e2e7123f4a84eff5c7c4602220ef0da16ca82eb4541050ffbdeadde0b623601e147b848469
@@ -0,0 +1,32 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ Gemfile.lock
28
+ .ruby-version
29
+ .ruby-gemset
30
+
31
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
32
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 David Michael Nelson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,130 @@
1
+ # Winston
2
+
3
+ [Constraint Satisfaction Problem](http://en.wikipedia.org/wiki/Constraint_satisfaction_problem) (CSP) implementation for Ruby.
4
+ It provides a useful way to solve problems like resource allocation or planning though a set of constraints.
5
+
6
+ The most common example of usage for CSPs is probably the game [Sudoku](http://en.wikipedia.org/wiki/Sudoku).
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'winston'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install winston
21
+
22
+ ## Usage
23
+
24
+ The problem consists of three sets of information: Domain, Variables and Constraints. It will try to determine a value
25
+ from the given domain for each variable that will attend all the constraints.
26
+
27
+ ```ruby
28
+ require 'winston'
29
+
30
+ csp = Winston::CSP.new
31
+
32
+ csp.add_variable :a, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
33
+ csp.add_variable :b, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
34
+ csp.add_variable :c, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
35
+
36
+ csp.add_constraint(:a, :c) { |a, c| a == c * 2 } # 'a' has to be double of 'c'.
37
+ csp.add_constraint(:a, :b) { |a, b| a > b } # 'a' has to be greater than 'b'.
38
+ csp.add_constraint(:b, :c) { |b, c| b > c } # 'b' has to be greater than 'c'.
39
+ csp.add_constraint(:b) { |b| b % 2 == 0 } # 'b' has to be even.
40
+
41
+ csp.solve
42
+ = { a: 6, b: 4, c: 3 }
43
+ ```
44
+
45
+ ### Variables and Domain
46
+
47
+ It's possible to preset values for variables, and in that case the problem would not try to determine values for
48
+ it, but it will take those values into account for validating the constraints.
49
+
50
+ ```ruby
51
+ csp.add_variable "my_var", value: "predefined value"
52
+ ```
53
+
54
+ And it's also possible to set the domain as `Proc` so it'd be evaluated on-demand.
55
+
56
+ ```ruby
57
+ csp.add_variable("other_var") { |var_name, csp| [:a, :b, :c ] }
58
+ # same as
59
+ csp.add_variable("other_var", domain: proc { |var_name, csp| [:a, :b, :c ] })
60
+ ```
61
+
62
+ ### Constraints
63
+
64
+ Constraints can be set for specific variables and would be evaluated only when all those variables are set and one
65
+ of them has changed; Or globals, in which case, they'd evaluated for every assignment.
66
+
67
+ ```ruby
68
+ csp.add_constraint(:a) { |a| a > 0 } # positive value
69
+
70
+ # the last argument passed to the block is always a map of assignments, in other words, the current
71
+ # state of the solution
72
+
73
+ csp.add_constraint(:a) do |a, assignments|
74
+ !assignments.reject { |name, value| name == :a }.values.include?(a) #checks if the value is not present on other variables
75
+ end
76
+
77
+ # a global constraint is evaluated for every assignment and the only argument it receives is a
78
+ # hash with all current assignments
79
+
80
+ csp.add_constraint do |assignments|
81
+ assignmets.values.uniq.size == assignments.keys.size # checks if every value is unique
82
+ end
83
+ ```
84
+
85
+ Constraint can be also set as their own objects, that's great for reusability.
86
+
87
+ ```ruby
88
+ csp.add_constraint constraint: MyConstraint.new(...)
89
+ # ...
90
+ csp.add_constraint constraint: Winston::Constraints::AllDifferent.new # built-in constraint, checks if all values are different from each other
91
+ ```
92
+
93
+ ### Problems without solution
94
+
95
+ ```ruby
96
+ require 'winston'
97
+
98
+ csp = Winston::CSP.new
99
+
100
+ csp.add_variable :a, domain: [1, 2]
101
+ csp.add_variable :b, domain: [1, 2]
102
+ csp.add_variable :c, domain: [1, 2]
103
+
104
+ csp.add_constraint constraint: Winston::Constraints::AllDifferent.new
105
+
106
+ csp.solve
107
+ = false
108
+ ```
109
+
110
+ **IMPORTANT NOTE: Depending on the number of variables and the size of the domain it can take a long time to test all different possibilities.
111
+ In that case it'll be recomendable to use of ways to reduce the number of iterations, for example, removing an item from a shared domain
112
+ when it is tested ( A `queue` type of structure, that would `pop` the value on the `each` block).**
113
+
114
+ ### More examples
115
+
116
+ Check the folder `specs/examples` for more usage examples.
117
+
118
+ ## TODOs / Nice-to-haves
119
+
120
+ - Create a DSL for setting up the problem
121
+ - Currently only algorithm to solve the CSP is Backtracking, implement other like Local search, Constraint propagation, ...
122
+ - Implement heuristics to improve search time (least constraining value, minimum remaining values,...)
123
+
124
+ ## Contributing
125
+
126
+ 1. Fork it
127
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
128
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
129
+ 4. Push to the branch (`git push origin my-new-feature`)
130
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ require 'winston/domain'
2
+ require 'winston/variable'
3
+ require 'winston/constraint'
4
+ require 'winston/backtrack'
5
+ require 'winston/csp'
6
+
7
+ require 'winston/constraints/all_different'
@@ -0,0 +1,40 @@
1
+ module Winston
2
+ class Backtrack
3
+ def initialize(csp)
4
+ @csp = csp
5
+ end
6
+
7
+ def search(assignments = {})
8
+ return assignments if complete?(assignments)
9
+ var = select_unassigned_variable(assignments)
10
+ domain_values(var).each do |value|
11
+ assigned = assignments.merge(var.name => value)
12
+ if valid?(var.name, assigned)
13
+ result = search(assigned)
14
+ return result if result
15
+ end
16
+ end
17
+ false
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :csp
23
+
24
+ def complete?(assignments)
25
+ assignments.size == csp.variables.size
26
+ end
27
+
28
+ def valid?(changed, assignments)
29
+ csp.validate(changed, assignments)
30
+ end
31
+
32
+ def select_unassigned_variable(assignments)
33
+ csp.variables.reject { |k,v| assignments.include?(k) }.each_value.first
34
+ end
35
+
36
+ def domain_values(var)
37
+ csp.variables[var.name].domain.values
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module Winston
2
+ class Constraint
3
+
4
+ def initialize(variables = nil, predicate = nil)
5
+ @variables = variables || []
6
+ @predicate = predicate
7
+ @global = @variables.empty?
8
+ end
9
+
10
+ def elegible_for?(changed_var, assignments)
11
+ @global || (@variables.include?(changed_var) && @variables.all? { |v| assignments.key? v })
12
+ end
13
+
14
+ def validate(assignments)
15
+ return false unless @predicate
16
+ @predicate.call(*assignments.values_at(*@variables), assignments)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Winston
2
+ module Constraints
3
+ class AllDifferent < Winston::Constraint
4
+ def validate(assignments)
5
+ assignments.values.uniq.size == assignments.size
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ module Winston
2
+ class CSP
3
+
4
+ attr_reader :variables, :constraints
5
+
6
+ def initialize
7
+ @variables = {}
8
+ @constraints = []
9
+ end
10
+
11
+ def solve(solver = Backtrack.new(self))
12
+ solver.search(var_assignments)
13
+ end
14
+
15
+ def add_variable(name, value: nil, domain: nil, &block)
16
+ domain = Domain.new(self, name, domain || block) unless value
17
+ variables[name] = Variable.new(name, value: value, domain: domain)
18
+ end
19
+
20
+ def add_constraint(*variables, constraint: nil, &block)
21
+ constraint ||= Constraint.new(variables, block)
22
+ constraints << constraint
23
+ end
24
+
25
+ def validate(changed_var, assignments)
26
+ constraints.each do |constraint|
27
+ return false if constraint.elegible_for?(changed_var, assignments) && !constraint.validate(assignments)
28
+ end
29
+ true
30
+ end
31
+
32
+ private
33
+
34
+ def var_assignments
35
+ @variables.reduce({}) do |assignments, (name, variable)|
36
+ assignments[name] = variable.value unless variable.value.nil?
37
+ assignments
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ module Winston
2
+ class Domain
3
+ def initialize(csp, variable, values)
4
+ @csp = csp
5
+ @variable = variable
6
+ @values = values
7
+ end
8
+
9
+ def values
10
+ return @values unless @values.is_a?(Proc)
11
+ @values.call(@variable, @csp)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Winston
2
+ class Variable
3
+ attr_reader :name, :value, :domain
4
+ attr_writer :value
5
+
6
+ def initialize(name, value:, domain:)
7
+ @name = name
8
+ @value = value
9
+ @domain = domain
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,38 @@
1
+ require "winston"
2
+
3
+ describe "Numbers Example" do
4
+ let(:csp) { Winston::CSP.new }
5
+
6
+ describe "'a' has to be double of 'c' and higher than 'b', 'b' has to be even and higher than 'c'" do
7
+ before do
8
+ csp.add_variable :a, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
9
+ csp.add_variable :b, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
10
+ csp.add_variable :c, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
11
+
12
+ csp.add_constraint(:a, :c) { |a, c| a == c * 2 }
13
+ csp.add_constraint(:a, :b) { |a, b| a > b }
14
+ csp.add_constraint(:b, :c) { |b, c| b > c }
15
+ csp.add_constraint(:b) { |b| b % 2 == 0 }
16
+ end
17
+
18
+ it "should return a valid solution" do
19
+ expect(csp.solve).to eq(a: 6, b: 4, c: 3)
20
+ end
21
+ end
22
+
23
+ describe "has to have different values" do
24
+ before do
25
+ csp.add_variable :a, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
26
+ csp.add_variable :b, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
27
+ csp.add_variable :c, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
28
+ csp.add_variable :d, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
29
+ csp.add_variable :e, domain: [1, 2, 3, 4, 5, 6, 7, 8, 9]
30
+
31
+ csp.add_constraint constraint: Winston::Constraints::AllDifferent.new
32
+ end
33
+
34
+ it "should return a valid solution" do
35
+ expect(csp.solve).to eq(a: 1, b: 2, c: 3, d: 4, e: 5)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ require "winston"
2
+
3
+ describe Winston::Backtrack do
4
+ let(:csp) { Winston::CSP.new }
5
+ subject { described_class.new(csp) }
6
+
7
+ describe "#search" do
8
+ context "simple assigment" do
9
+ before do
10
+ csp.add_variable :a, domain: [1, 2, 3, 4]
11
+ csp.add_variable :b, domain: [1, 2, 3, 4]
12
+ csp.add_variable :c, domain: [1, 2, 3, 4]
13
+ end
14
+
15
+ it "should assign variables to the first acceptable value" do
16
+ expect(subject.search).to eq(a: 1, b: 1, c: 1)
17
+ end
18
+
19
+ it "should assign variables to the first acceptable value respecting variables that already have a value" do
20
+ expect(subject.search(b: 3)).to eq(a: 1, b: 3, c: 1)
21
+ end
22
+
23
+ context "with constraints" do
24
+ before do
25
+ csp.add_constraint(:a, :b) { |a,b| a > b }
26
+ csp.add_constraint(:b, :c) { |b,c| b > c }
27
+ end
28
+
29
+ it "should assign variables to the first acceptable value" do
30
+ expect(subject.search).to eq(a: 3, b: 2, c: 1)
31
+ end
32
+
33
+ it "should assign variables to the first acceptable value" do
34
+ expect(subject.search(b: 3)).to eq(a: 4, b: 3, c: 1)
35
+ end
36
+
37
+ it "should return false when it cannot fufill the constraints" do
38
+ expect(subject.search(c: 3)).to be(false)
39
+ end
40
+
41
+ it "should return false when it cannot fufill the constraints" do
42
+ csp.add_constraint(:a, :c) { |a,c| a == c * 10 }
43
+ expect(subject.search).to be(false)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,99 @@
1
+ require "winston"
2
+
3
+ describe Winston::Constraint do
4
+
5
+ let(:variables) { nil }
6
+ let(:predicate) { nil }
7
+ subject { described_class.new(variables, predicate) }
8
+
9
+ describe "#elegible_for?" do
10
+ context "global" do
11
+ it "should be elegible for everything" do
12
+ expect(subject.elegible_for?(:a, {})).to be(true)
13
+ expect(subject.elegible_for?(:b, { a: 1 })).to be(true)
14
+ end
15
+ end
16
+
17
+ context "for specific variable" do
18
+ let(:variables) { [:a] }
19
+
20
+ it "should return true when that variable is changed" do
21
+ expect(subject.elegible_for?(:a, { a: nil })).to be(true)
22
+ end
23
+
24
+ it "should return false when that variable isn't the one changed" do
25
+ expect(subject.elegible_for?(:b, { a: 1, b: 2 })).to be(false)
26
+ end
27
+
28
+ it "should return false when that variable is changed but doesn't have a value" do
29
+ expect(subject.elegible_for?(:a, { b: 2 })).to be(false)
30
+ end
31
+ end
32
+
33
+ context "for multiple variables" do
34
+ let(:variables) { [:a, :b] }
35
+
36
+ it "should return true when one of those variables is changed" do
37
+ expect(subject.elegible_for?(:a, { a: 1, b: nil })).to be(true)
38
+ end
39
+
40
+ it "should return false when one of those variables isn't the one changed" do
41
+ expect(subject.elegible_for?(:c, { a: 1, b: 2 })).to be(false)
42
+ end
43
+
44
+ it "should return false when one of those variables is changed but doesn't have a value for every one of them" do
45
+ expect(subject.elegible_for?(:b, { b: 2 })).to be(false)
46
+ end
47
+
48
+ it "should return false when one of those variables is changed but doesn't have a value for every one of them" do
49
+ expect(subject.elegible_for?(:a, { b: 2 })).to be(false)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "#validate" do
55
+ context "no predicate is given" do
56
+ it "should be considerated invalid" do
57
+ expect(subject.validate(a: 1)).to be(false)
58
+ end
59
+ end
60
+
61
+ context "when a predicate is given" do
62
+ context "on a global constraint" do
63
+ let(:predicate) do
64
+ proc { |assignments| assignments[:a] > assignments[:b] }
65
+ end
66
+
67
+ it "should evaluate that predicate" do
68
+ expect(subject.validate(a: 2, b: 1)).to be(true)
69
+ expect(subject.validate(a: 1, b: 2)).to be(false)
70
+ end
71
+ end
72
+
73
+ context "on an unary constraint" do
74
+ let(:variables) { [:a] }
75
+ let(:predicate) do
76
+ proc { |a, assignments| a % 2 == 0 && !assignments.reject { |k,_| k == :a }.values.include?(a) }
77
+ end
78
+
79
+ it "should evaluate that predicate" do
80
+ expect(subject.validate(a: 2, b: 1)).to be(true)
81
+ expect(subject.validate(a: 1, b: 2)).to be(false)
82
+ expect(subject.validate(a: 2, b: 2)).to be(false)
83
+ end
84
+ end
85
+
86
+ context "on a n-ary constraint" do
87
+ let(:variables) { [:a, :b, :c] }
88
+ let(:predicate) do
89
+ proc { |a, b, c, assignments| a > b && b > c }
90
+ end
91
+
92
+ it "should evaluate that predicate" do
93
+ expect(subject.validate(a: 2, b: 1, c: 0)).to be(true)
94
+ expect(subject.validate(a: 1, b: 2, c: 1)).to be(false)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,22 @@
1
+ require "winston"
2
+
3
+ describe Winston::Constraints::AllDifferent do
4
+ subject { described_class.new }
5
+
6
+ describe "#elegible_for?" do
7
+ it "should be elegible for everything" do
8
+ expect(subject.elegible_for?(:a, {})).to be(true)
9
+ expect(subject.elegible_for?(:b, { a: 1 })).to be(true)
10
+ end
11
+ end
12
+
13
+ describe "#validate" do
14
+ it "should return 'true' when all values are unique" do
15
+ expect(subject.validate(a: 1, b: 2, c: 3, d: 4)).to be(true)
16
+ end
17
+
18
+ it "should return 'false' when not all values are unique" do
19
+ expect(subject.validate(a: 1, b: 2, c: 2, d: 4)).to be(false)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ require "winston"
2
+
3
+ describe Winston::CSP do
4
+ subject { described_class.new }
5
+
6
+ describe "#add_variable" do
7
+ let(:domain) { double("Domain") }
8
+
9
+ it "should add variable definitions to the problem" do
10
+ expect(Winston::Domain).to_not receive(:new)
11
+ subject.add_variable :a, value: 1
12
+ expect(subject.variables[:a]).to have_attributes(value: 1, domain: nil)
13
+ end
14
+
15
+ it "should add without value and a static domain when it is given" do
16
+ expect(Winston::Domain).to receive(:new).with(subject, :b, [2, 3]).once.and_return(domain)
17
+ subject.add_variable :b, domain: [2, 3]
18
+ expect(subject.variables[:b]).to have_attributes(value: nil, domain: domain)
19
+ end
20
+
21
+ it "should add without value and a dynamic domain when it is given" do
22
+ expect(Winston::Domain).to receive(:new).with(subject, :c, an_instance_of(Proc)).once
23
+ subject.add_variable(:c) { |csp| [2, 3, 4] }
24
+ expect(subject.variables[:c]).to have_attributes(value: nil)
25
+ end
26
+ end
27
+
28
+ describe "#add_constraint" do
29
+ let(:constraint) { double("Constraint") }
30
+ it "should build a constraint for the given block" do
31
+ expect(Winston::Constraint).to receive(:new).with([:a, :b], an_instance_of(Proc)).once.and_return(constraint)
32
+ subject.add_constraint(:a, :b) { true }
33
+ expect(subject.constraints).to include(constraint)
34
+ end
35
+
36
+ it "should add the already build constraint when given" do
37
+ expect(Winston::Constraint).to_not receive(:new)
38
+ subject.add_constraint(constraint: constraint)
39
+ expect(subject.constraints).to include(constraint)
40
+ end
41
+ end
42
+
43
+ describe "#validate" do
44
+ it "should return true when there aren't any constraints" do
45
+ expect(subject.validate(:var, {})).to be(true)
46
+ end
47
+
48
+ it "should return false if one of the constraints returns invalid" do
49
+ subject.add_constraint(:a) { true }
50
+ subject.add_constraint(:a) { false }
51
+
52
+ expect(subject.validate(:a, {a: 1})).to be(false)
53
+ end
54
+
55
+ it "should not attempt to validate ineligible constraints" do
56
+ subject.add_constraint(:a) { true }
57
+ subject.add_constraint(:b) { false }
58
+
59
+ expect(subject.validate(:a, { a: 1 , b: 2 })).to be(true)
60
+ end
61
+ end
62
+
63
+ describe "#solve" do
64
+ let(:solver) { double("Solver") }
65
+ before do
66
+ subject.add_variable :a, value: 1
67
+ subject.add_variable :b, domain: [1, 2]
68
+ end
69
+
70
+ it "should pass a collection of preset variables to the solver" do
71
+ expect(solver).to receive(:search).with(a: 1)
72
+ subject.solve(solver)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ require "winston"
2
+
3
+ describe Winston::Domain do
4
+ let(:csp) { double("CSP") }
5
+ let(:variable) { :var }
6
+
7
+ subject { described_class.new(csp, variable, values) }
8
+
9
+ describe "#values" do
10
+ context "when given 'values' is a collection" do
11
+ let(:values) { [1, 2, 3] }
12
+
13
+ it "should return that collection" do
14
+ expect(subject.values).to eq([1, 2, 3])
15
+ end
16
+ end
17
+
18
+ context "when given 'values' is a proc" do
19
+ let(:values) do
20
+ i = 0
21
+ proc do |given_variable, given_csp|
22
+ expect(given_variable).to eq(variable)
23
+ expect(given_csp).to eq(csp)
24
+
25
+ [i += 1]
26
+ end
27
+ end
28
+
29
+ it "should return the result of the evatualtion of that proc" do
30
+ expect(subject.values).to eq([1])
31
+ expect(subject.values).to eq([2])
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ require "winston"
2
+
3
+ describe Winston::Variable do
4
+
5
+ subject { described_class.new("my_var", value: 1, domain: [1, 2, 3]) }
6
+
7
+ it { is_expected.to have_attributes(name: "my_var", value: 1, domain: [1, 2, 3]) }
8
+
9
+ describe "#value=" do
10
+ before { subject.value = "new value" }
11
+
12
+ it { is_expected.to have_attributes(value: "new value") }
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'winston'
3
+ gem.version = '0.0.1'
4
+ gem.authors = ['David Michael Nelson']
5
+ gem.homepage = 'http://github.com/dmnelson/winston'
6
+
7
+ gem.summary = 'Constraint Satisfaction Problem (CSP) implementation for Ruby'
8
+ gem.description = gem.summary
9
+ gem.license = 'MIT'
10
+
11
+ gem.files = `git ls-files`.split($/)
12
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.require_paths = ["lib"]
15
+
16
+ gem.add_development_dependency "bundler", "~> 1.3"
17
+ gem.add_development_dependency "rake"
18
+ gem.add_development_dependency 'rspec'
19
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: winston
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - David Michael Nelson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Constraint Satisfaction Problem (CSP) implementation for Ruby
56
+ email:
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - lib/winston.rb
67
+ - lib/winston/backtrack.rb
68
+ - lib/winston/constraint.rb
69
+ - lib/winston/constraints/all_different.rb
70
+ - lib/winston/csp.rb
71
+ - lib/winston/domain.rb
72
+ - lib/winston/variable.rb
73
+ - spec/examples/numbers_spec.rb
74
+ - spec/winston/backtrack_spec.rb
75
+ - spec/winston/constraint_spec.rb
76
+ - spec/winston/constraints/all_different_spec.rb
77
+ - spec/winston/csp_spec.rb
78
+ - spec/winston/domain_spec.rb
79
+ - spec/winston/variable_spec.rb
80
+ - winston.gemspec
81
+ homepage: http://github.com/dmnelson/winston
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.2.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Constraint Satisfaction Problem (CSP) implementation for Ruby
105
+ test_files:
106
+ - spec/examples/numbers_spec.rb
107
+ - spec/winston/backtrack_spec.rb
108
+ - spec/winston/constraint_spec.rb
109
+ - spec/winston/constraints/all_different_spec.rb
110
+ - spec/winston/csp_spec.rb
111
+ - spec/winston/domain_spec.rb
112
+ - spec/winston/variable_spec.rb