pincushion 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pincushion.rb +37 -9
- data/lib/pincushion/plugins.rb +20 -0
- data/lib/pincushion/plugins/csv_serializer.rb +19 -2
- data/lib/pincushion/plugins/json_serializer.rb +11 -3
- data/lib/pincushion/version.rb +1 -3
- data/spec/pincushion_spec.rb +95 -0
- data/spec/spec_helper.rb +4 -0
- metadata +40 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8eab64e433918cb3f0881c57abb7d09a4dd1bfac
|
4
|
+
data.tar.gz: 4ca030d28f2cf4ef8b270d9a47e116cdf4a1e314
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb77a2fd89d401c263b68ab334ee3a5eeeefa816d9578be94bb537b800c7d7abaad7169c30dbb7ce44a8dfd1637699c9d9d895e46324f0a851396382c29f6a61
|
7
|
+
data.tar.gz: 1b6df11775ecd620373e87767ae3e1c927541a0d9d0d145c0b56262ff4e2d357e09b151102563bf61866fdaaa4da8580a2e7d689526ec3ec40fc622f47e44c71
|
data/lib/pincushion.rb
CHANGED
@@ -2,18 +2,42 @@ require 'set'
|
|
2
2
|
require 'pincushion/plugins'
|
3
3
|
|
4
4
|
module Pincushion
|
5
|
+
def self.from_rows(rows)
|
6
|
+
Module.new.module_eval do
|
7
|
+
include Pincushion
|
8
|
+
|
9
|
+
predicates = rows
|
10
|
+
.reduce(Set.new) { |a, e| a.merge(e.keys) }
|
11
|
+
.delete(:identifier)
|
12
|
+
predicates(*predicates)
|
13
|
+
|
14
|
+
rows.each do |row|
|
15
|
+
row = row.dup
|
16
|
+
identifier = row.delete(:identifier)
|
17
|
+
true_predicates = row.each_pair.select { |_, v| v }.map { |k, _| k }
|
18
|
+
that_is(*true_predicates).named(identifier)
|
19
|
+
end
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.validate(mod, preds)
|
26
|
+
violations = Set.new(preds) - mod.predicates
|
27
|
+
return if violations.empty?
|
28
|
+
fail MissingPredicateError,
|
29
|
+
"Tried to set a value for unregistered predicate(s): "\
|
30
|
+
"#{violations.inspect}"
|
31
|
+
end
|
32
|
+
|
5
33
|
module RootModuleMethods
|
6
34
|
include Plugins
|
7
35
|
|
8
36
|
attr_reader :identifiers
|
9
37
|
|
10
|
-
def
|
11
|
-
identifiers.map
|
12
|
-
|
13
|
-
|
14
|
-
def all_identifiers_predicates_rows
|
15
|
-
identifiers.flat_map do |id, cls|
|
16
|
-
cls.new(id).all_predicates_hash.map { |k, v| [id, k, v] }
|
38
|
+
def rows
|
39
|
+
identifiers.map do |id, cls|
|
40
|
+
{ identifier: id }.merge(cls.new(id).all_predicates_hash)
|
17
41
|
end
|
18
42
|
end
|
19
43
|
|
@@ -26,9 +50,9 @@ module Pincushion
|
|
26
50
|
end
|
27
51
|
|
28
52
|
def predicates(*preds)
|
29
|
-
return @predicates if preds.empty?
|
53
|
+
return (@predicates || Set.new) if preds.empty?
|
30
54
|
fail "Predicates can't be changed after initialization" if @predicates
|
31
|
-
@predicates = Set.new
|
55
|
+
@predicates = Set.new(preds)
|
32
56
|
is_not(*@predicates)
|
33
57
|
@predicates.each do |predicate|
|
34
58
|
alias_method(:"is_#{predicate}?", :"#{predicate}?")
|
@@ -53,11 +77,13 @@ module Pincushion
|
|
53
77
|
end
|
54
78
|
|
55
79
|
def is(*preds)
|
80
|
+
Pincushion.validate(predicate_pincushion_root, preds)
|
56
81
|
preds.each { |pred| define_method(:"#{pred}?") { true } }
|
57
82
|
self
|
58
83
|
end
|
59
84
|
|
60
85
|
def is_not(*preds)
|
86
|
+
Pincushion.validate(predicate_pincushion_root, preds)
|
61
87
|
preds.each { |pred| define_method(:"#{pred}?") { false } }
|
62
88
|
self
|
63
89
|
end
|
@@ -76,6 +102,7 @@ module Pincushion
|
|
76
102
|
end
|
77
103
|
|
78
104
|
def that_are(*preds)
|
105
|
+
Pincushion.validate(self, preds)
|
79
106
|
mod = Module.new
|
80
107
|
mod.include self
|
81
108
|
mod.is(*preds)
|
@@ -83,6 +110,7 @@ module Pincushion
|
|
83
110
|
end
|
84
111
|
|
85
112
|
def that_is(*preds)
|
113
|
+
Pincushion.validate(self, preds)
|
86
114
|
klass = Class.new
|
87
115
|
klass.include self
|
88
116
|
klass.is(*preds)
|
data/lib/pincushion/plugins.rb
CHANGED
@@ -1,4 +1,20 @@
|
|
1
1
|
module Pincushion
|
2
|
+
def self.plugins
|
3
|
+
@plugins || []
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.plugin(name)
|
7
|
+
require "pincushion/plugins/#{name}"
|
8
|
+
mod = Plugins.const_get(Plugins.camelize(name))
|
9
|
+
extend mod::PincushionMethods if defined?(mod::PincushionMethods)
|
10
|
+
@plugins ||= []
|
11
|
+
@plugins << name
|
12
|
+
rescue LoadError
|
13
|
+
raise LoadError, "Plugin not found: #{name}"
|
14
|
+
rescue NameError => e
|
15
|
+
raise NameError, "#{e} for plugin: #{name}"
|
16
|
+
end
|
17
|
+
|
2
18
|
module Plugins
|
3
19
|
def self.camelize(string)
|
4
20
|
string.to_s
|
@@ -6,12 +22,16 @@ module Pincushion
|
|
6
22
|
.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase }
|
7
23
|
end
|
8
24
|
|
25
|
+
attr_reader :plugins
|
26
|
+
|
9
27
|
def plugin(name)
|
10
28
|
require "pincushion/plugins/#{name}"
|
11
29
|
mod = Plugins.const_get(Plugins.camelize(name))
|
12
30
|
extend mod::ModuleMethods if defined?(mod::ModuleMethods)
|
13
31
|
extend mod::RootModuleMethods if defined?(mod::RootModuleMethods)
|
14
32
|
include mod::InstanceMethods if defined?(mod::InstanceMethods)
|
33
|
+
@plugins ||= []
|
34
|
+
@plugins << name
|
15
35
|
rescue LoadError
|
16
36
|
raise LoadError, "Plugin not found: #{name}"
|
17
37
|
rescue NameError => e
|
@@ -1,12 +1,29 @@
|
|
1
1
|
require 'csv'
|
2
2
|
|
3
3
|
module Pincushion
|
4
|
+
def self.from_csv(csv, *args)
|
5
|
+
args << {} unless args.last.is_a?(Hash)
|
6
|
+
args.last.merge!(Plugins::CsvSerializer::OPTS)
|
7
|
+
from_rows(CSV.parse(csv, *args).map(&:to_h))
|
8
|
+
end
|
9
|
+
|
4
10
|
module Plugins
|
5
11
|
module CsvSerializer
|
12
|
+
OPTS = {
|
13
|
+
headers: true,
|
14
|
+
header_converters: :symbol,
|
15
|
+
converters: lambda { |string|
|
16
|
+
case string
|
17
|
+
when "true" then true
|
18
|
+
when "false" then false
|
19
|
+
else string
|
20
|
+
end
|
21
|
+
}
|
22
|
+
}.freeze
|
23
|
+
|
6
24
|
module RootModuleMethods
|
7
25
|
def to_csv(*args, **kwargs)
|
8
|
-
|
9
|
-
kwargs[:headers] ||= [:identifier, :predicate, :value]
|
26
|
+
kwargs[:headers] ||= [:identifier, *predicates]
|
10
27
|
|
11
28
|
CSV.generate(*args, **kwargs) do |csv|
|
12
29
|
rows.each { |row| csv << row }
|
@@ -1,11 +1,19 @@
|
|
1
|
-
require 'multi_json'
|
2
|
-
|
3
1
|
module Pincushion
|
4
2
|
module Plugins
|
5
3
|
module JsonSerializer
|
4
|
+
OPTS = { symbolize_names: true }
|
5
|
+
|
6
|
+
module PincushionMethods
|
7
|
+
def from_json(json, *args)
|
8
|
+
args << {} unless args.last.is_a?(Hash)
|
9
|
+
args.last.merge!(OPTS)
|
10
|
+
from_rows(JSON.parse(json, *args))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
module RootModuleMethods
|
7
15
|
def to_json(*args)
|
8
|
-
|
16
|
+
JSON.dump(rows, *args)
|
9
17
|
end
|
10
18
|
end # module RootModuleMethods
|
11
19
|
end # module JsonSerializer
|
data/lib/pincushion/version.rb
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "json"
|
3
|
+
require "pincushion"
|
4
|
+
require "pincushion/version"
|
5
|
+
|
6
|
+
describe Pincushion do
|
7
|
+
let(:klass) { Pincushion }
|
8
|
+
|
9
|
+
let(:animal_data) do
|
10
|
+
[
|
11
|
+
{ identifier: "Mee-mow", carnivore: true, herbivore: false },
|
12
|
+
{ identifier: "Jake", carnivore: true, herbivore: true },
|
13
|
+
{ identifier: "B-Mo", carnivore: false, herbivore: false }
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:animal_data_csv) do
|
18
|
+
"identifier,carnivore,herbivore\n"\
|
19
|
+
"Mee-mow,true,false\n"\
|
20
|
+
"Jake,true,true\n"\
|
21
|
+
"B-Mo,false,false\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:animal_data_json) do
|
25
|
+
"[{\"identifier\":\"Mee-mow\",\"carnivore\":true,\"herbivore\":false},"\
|
26
|
+
"{\"identifier\":\"Jake\",\"carnivore\":true,\"herbivore\":true},"\
|
27
|
+
"{\"identifier\":\"B-Mo\",\"carnivore\":false,\"herbivore\":false}]"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "has a version number" do
|
31
|
+
refute_nil ::Pincushion::VERSION
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can be used to define a category with properties" do
|
35
|
+
animals = Module.new
|
36
|
+
animals.include Pincushion
|
37
|
+
animals.predicates :carnivore, :herbivore
|
38
|
+
cat = animals.that_is(:carnivore).named("Mee-mow")
|
39
|
+
mittens = animals.find("Mee-mow")
|
40
|
+
assert_equal mittens.class, cat
|
41
|
+
assert mittens.carnivore?
|
42
|
+
refute mittens.herbivore?
|
43
|
+
end
|
44
|
+
|
45
|
+
it "doesn't allow unregistered predicates" do
|
46
|
+
animals = Module.new
|
47
|
+
animals.include Pincushion
|
48
|
+
animals.predicates :herbivore
|
49
|
+
|
50
|
+
assert_raises Pincushion::MissingPredicateError do
|
51
|
+
animals.that_is(:carnivore)
|
52
|
+
end
|
53
|
+
|
54
|
+
assert_raises Pincushion::MissingPredicateError do
|
55
|
+
cat = animals.that_is
|
56
|
+
cat.is(:carnivore)
|
57
|
+
end
|
58
|
+
|
59
|
+
assert_raises Pincushion::MissingPredicateError do
|
60
|
+
cat = animals.that_is
|
61
|
+
cat.is_not(:carnivore)
|
62
|
+
end
|
63
|
+
|
64
|
+
assert_raises Pincushion::MissingPredicateError do
|
65
|
+
animals.that_are(:carnivore)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "doesn't allow unregistered predicates (empty set)" do
|
70
|
+
animals = Module.new
|
71
|
+
animals.include Pincushion
|
72
|
+
assert_raises Pincushion::MissingPredicateError do
|
73
|
+
animals.that_is(:carnivore)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "round-trips to and from arrays of hashes" do
|
78
|
+
animals = Pincushion.from_rows(animal_data)
|
79
|
+
assert_equal animals.rows, animal_data
|
80
|
+
end
|
81
|
+
|
82
|
+
it "round-trips CSV with the csv_serializer plugin" do
|
83
|
+
Pincushion.plugin :csv_serializer
|
84
|
+
animals = Pincushion.from_csv(animal_data_csv)
|
85
|
+
animals.plugin :csv_serializer
|
86
|
+
assert_equal animals.to_csv(write_headers: true), animal_data_csv
|
87
|
+
end
|
88
|
+
|
89
|
+
it "round-trips JSON with the json_serializer plugin" do
|
90
|
+
Pincushion.plugin :json_serializer
|
91
|
+
animals = Pincushion.from_json(animal_data_json)
|
92
|
+
animals.plugin :json_serializer
|
93
|
+
assert_equal animals.to_json, animal_data_json
|
94
|
+
end
|
95
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,29 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pincushion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Miller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
27
55
|
description:
|
28
56
|
email: bmiller@rackspace.com
|
29
57
|
executables: []
|
@@ -35,6 +63,8 @@ files:
|
|
35
63
|
- lib/pincushion/plugins/csv_serializer.rb
|
36
64
|
- lib/pincushion/plugins/json_serializer.rb
|
37
65
|
- lib/pincushion/version.rb
|
66
|
+
- spec/pincushion_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
38
68
|
homepage: https://github.com/bjmllr/pincushion
|
39
69
|
licenses:
|
40
70
|
- MIT
|
@@ -55,8 +85,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
85
|
version: '0'
|
56
86
|
requirements: []
|
57
87
|
rubyforge_project:
|
58
|
-
rubygems_version: 2.
|
88
|
+
rubygems_version: 2.5.1
|
59
89
|
signing_key:
|
60
90
|
specification_version: 4
|
61
91
|
summary: Predicate-centric classification toolkit
|
62
|
-
test_files:
|
92
|
+
test_files:
|
93
|
+
- spec/pincushion_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
has_rdoc:
|