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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d51bc5faf8cad8112f822aa6b99d40473790720
4
- data.tar.gz: 32bc18b5c133c5862ed9a10b0f9f7e75e33287f3
3
+ metadata.gz: 8eab64e433918cb3f0881c57abb7d09a4dd1bfac
4
+ data.tar.gz: 4ca030d28f2cf4ef8b270d9a47e116cdf4a1e314
5
5
  SHA512:
6
- metadata.gz: 32db6265a455714d8e50303ca644129632d7e510d368fc0ab161770bc72f5eed14e47a95f4ae2c5b67f5f95fba51c9a01e5de4cf1b439dd540ba66f16c20df4b
7
- data.tar.gz: a5abddff7882701b6e681aa29b406dfad111450a4f24eacf2057215746ca766cdd06eb13867d87187c32c8ecfc682bbd4229478720e7c0d93ce3208acf480603
6
+ metadata.gz: cb77a2fd89d401c263b68ab334ee3a5eeeefa816d9578be94bb537b800c7d7abaad7169c30dbb7ce44a8dfd1637699c9d9d895e46324f0a851396382c29f6a61
7
+ data.tar.gz: 1b6df11775ecd620373e87767ae3e1c927541a0d9d0d145c0b56262ff4e2d357e09b151102563bf61866fdaaa4da8580a2e7d689526ec3ec40fc622f47e44c71
@@ -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 all_identifiers_predicates_hashes
11
- identifiers.map { |k, v| [k, v.all_predicates_hash] }.to_h
12
- end
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 preds
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)
@@ -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
- rows = all_identifiers_predicates_rows
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
- MultiJson.dump(all_identifiers_predicates_hashes, *args)
16
+ JSON.dump(rows, *args)
9
17
  end
10
18
  end # module RootModuleMethods
11
19
  end # module JsonSerializer
@@ -1,5 +1,3 @@
1
1
  module Pincushion
2
- def self.version
3
- '0.0.1'
4
- end
2
+ VERSION = "0.1.0"
5
3
  end # module Pincushion
@@ -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
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+
3
+ require "minitest/spec"
4
+ require "minitest/autorun"
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.1
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: 2015-09-04 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
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: '3.0'
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.4.5.1
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: