winston 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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