triad 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b102ba1a28f4a9bf80e239083ec5cfa6ecfa02cd
4
+ data.tar.gz: a2fbdcae55dae2126fdc315060bc2f9109b7a2aa
5
+ SHA512:
6
+ metadata.gz: 42e73cadff398ec9c7c751be0f4492990b0b2f7ac122694d750684ded08511f1f60e8a3addad520a61d2bf18e10a1467f23c4b3a13d88d9c037cac0610b278d5
7
+ data.tar.gz: eef77531a5080e84015c3c2664dba5f3222107a9d7c2b4139dcc21814deec4117827657706b8f968c42952fe69df33bdf1e3f45057f9e6a679b61c1c4e184a81
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - ruby-head
7
+ - jruby-head
8
+ - rbx-19mode
9
+ env:
10
+ - COVERALLS=true
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
14
+ - rvm: jruby-head
15
+ - rvm: rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in triad.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "rake"
8
+ gem "simplecov"
9
+ gem "minitest"
10
+ gem "coveralls"
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 'Jim Gay'
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Triad
2
+
3
+ [![Build Status](https://travis-ci.org/saturnflyer/triad.png?branch=master)](https://travis-ci.org/saturnflyer/triad)
4
+ [![Code Climate](https://codeclimate.com/github/saturnflyer/triad.png)](https://codeclimate.com/github/saturnflyer/triad)
5
+ [![Coverage Status](https://coveralls.io/repos/saturnflyer/triad/badge.png)](https://coveralls.io/r/saturnflyer/triad)
6
+ [![Gem Version](https://badge.fury.io/rb/triad.png)](http://badge.fury.io/rb/triad)
7
+
8
+ A Triad is like a Set, or a collection of three-part arrays.
9
+
10
+ A Triad is a collection of items each with a `key`, `descriptor`, and `value`.
11
+
12
+ Each `key` must be a unique symbol.
13
+ Each `descriptor` must be a string.
14
+ Each `value` must not be a symbol nor a string.
15
+
16
+ ```ruby
17
+ user = Object.new
18
+
19
+ map = Triad.new
20
+ map << [:admin, 'Admin', user]
21
+
22
+ map.keys('Admin') #=> [:admin]
23
+ map.values('Admin') #=> [user]
24
+ map.descriptors('Admin') #=> ['Admin'] or raise DescriptorNotPresent
25
+
26
+ map.descriptors(user) #=> ['Admin']
27
+ map.keys(user) #=> [:admin]
28
+ map.values(user) #=> [user] or raise ValueNotPresent
29
+
30
+ map.values(:admin) #=> [user]
31
+ map.descriptors(:admin) #=> ['Admin']
32
+ map.keys(:admin) #=> [:admin] or raise KeyNotPresent
33
+
34
+ map.each do |key, descriptor, value|
35
+ #...
36
+ end
37
+ ```
38
+
39
+ ## Installation
40
+
41
+ Add this line to your application's Gemfile:
42
+
43
+ ```ruby
44
+ gem 'triad'
45
+ ```
46
+
47
+ And then execute:
48
+
49
+ $ bundle
50
+
51
+ Or install it yourself as:
52
+
53
+ $ gem install triad
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,3 @@
1
+ class Triad
2
+ VERSION = "0.1.0"
3
+ end
data/lib/triad.rb ADDED
@@ -0,0 +1,87 @@
1
+ require "triad/version"
2
+
3
+ class Triad
4
+ include Enumerable
5
+
6
+ class InvalidAddition < StandardError
7
+ def message
8
+ "your array length must be 3"
9
+ end
10
+ end
11
+ class ValueNotPresent < StandardError; end
12
+ class DescriptorNotPresent < StandardError; end
13
+ class KeyNotPresent < StandardError; end
14
+
15
+ # stored as {key => ['Descriptor', value]}
16
+ def initialize(*args)
17
+ @storage = {}
18
+ end
19
+ attr_reader :storage
20
+ private :storage
21
+
22
+ def keys(arg)
23
+ with_interest(arg).map{|key, _, _| key }
24
+ end
25
+
26
+ def descriptors(arg)
27
+ with_interest(arg).map{|_, descriptor, _| descriptor }
28
+ end
29
+
30
+ def values(arg)
31
+ with_interest(arg).map{|_, _, value| value }
32
+ end
33
+
34
+ def <<(array)
35
+ array_key = array.find{|item| item.is_a?(Symbol) }
36
+ raise InvalidAddition if array.length != 3 || key_exists?(array_key)
37
+
38
+ array_descriptor = array.find{|item| item.is_a?(String) }
39
+ array_value = array.find{|item| !item.is_a?(String) && !item.is_a?(Symbol) }
40
+
41
+ storage[array_key] = [array_descriptor, array_value]
42
+ self
43
+ end
44
+
45
+ def each
46
+ storage.each do |key, (descriptor, value)|
47
+ yield key, descriptor, value
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def key_exists?(key)
54
+ storage.has_key?(key)
55
+ end
56
+
57
+ def positions
58
+ [:key, :descriptor, :value]
59
+ end
60
+
61
+ def argument_type(arg)
62
+ case arg
63
+ when Symbol then :key
64
+ when String then :descriptor
65
+ else :value
66
+ end
67
+ end
68
+
69
+ def raise_error(type)
70
+ error_name = type.to_s.gsub(/(?:^|_)([a-z])/) { $1.upcase }
71
+ error_class = Triad.const_get("#{error_name}NotPresent")
72
+ raise error_class.new
73
+ end
74
+
75
+ def with_interest(interest)
76
+ type = argument_type(interest)
77
+ index = positions.index(type)
78
+
79
+ lookup = storage.select{|key, array|
80
+ [key, *array][index] == interest
81
+ }.map{|key, array| [key, *array] }
82
+
83
+ raise_error(type) if lookup.empty?
84
+
85
+ lookup
86
+ end
87
+ end
@@ -0,0 +1,13 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter 'test'
4
+ end
5
+ require 'coveralls'
6
+
7
+ if ENV['COVERALLS']
8
+ Coveralls.wear!
9
+ end
10
+
11
+ require 'minitest/autorun'
12
+
13
+ require 'triad'
@@ -0,0 +1,173 @@
1
+ require 'test_helper'
2
+
3
+ describe Triad, '#<<' do
4
+ let(:triad){ Triad.new }
5
+
6
+ it 'shovels 3 item arrays' do
7
+ assert triad << [:test, 'Test', Object.new]
8
+ end
9
+
10
+ it 'rejects arrays with more than 3 items' do
11
+ error = assert_raises(Triad::InvalidAddition){
12
+ triad << [:test, 'Test', Object.new, 'Other']
13
+ }
14
+ assert_match /array length must be 3/, error.message
15
+ end
16
+
17
+ it 'rejects arrays with fewer than 3 items' do
18
+ assert_raises(Triad::InvalidAddition){
19
+ triad << [:test, 'Test']
20
+ }
21
+ end
22
+
23
+ it 'rejects arrays with an existing key' do
24
+ triad << [:test, 'Test', Object.new]
25
+ assert_raises(Triad::InvalidAddition){
26
+ triad << [:test, 'More', Object.new]
27
+ }
28
+ end
29
+
30
+ it 'assigns symbol as key' do
31
+ object = Object.new
32
+ triad << ['OutOfOrder', object, :surprise]
33
+ assert_equal [:surprise], triad.keys('OutOfOrder')
34
+ assert_equal [:surprise], triad.keys(object)
35
+ end
36
+
37
+ it 'assigns string as descriptor' do
38
+ object = Object.new
39
+ triad << ['OutOfOrder', object, :surprise]
40
+ assert_equal ['OutOfOrder'], triad.descriptors(:surprise)
41
+ assert_equal ['OutOfOrder'], triad.descriptors(object)
42
+ end
43
+
44
+ it 'assigns non-symbol, non-string objects as value' do
45
+ object = Object.new
46
+ triad << ['OutOfOrder', object, :surprise]
47
+ assert_equal [object], triad.values(:surprise)
48
+ assert_equal [object], triad.values('OutOfOrder')
49
+ end
50
+ end
51
+
52
+ describe Triad, '#keys' do
53
+ let(:user){ Object.new }
54
+ let(:triad){
55
+ tri = Triad.new
56
+ tri << [:admin, 'Admin', user]
57
+ tri
58
+ }
59
+
60
+ it 'returns the key for the given descriptor' do
61
+ assert_equal [:admin], triad.keys('Admin')
62
+ end
63
+
64
+ it 'returns the key for the given value' do
65
+ assert_equal [:admin], triad.keys(user)
66
+ end
67
+
68
+ it 'returns the keys for the given key' do
69
+ assert_equal [:admin], triad.keys(:admin)
70
+ end
71
+
72
+ it 'errors when the given key is not found' do
73
+ assert_raises(Triad::KeyNotPresent){
74
+ triad.keys(:invalid_key)
75
+ }
76
+ end
77
+
78
+ it 'errors when the given descriptor is not found' do
79
+ assert_raises(Triad::DescriptorNotPresent){
80
+ triad.keys('Invalid Descriptor')
81
+ }
82
+ end
83
+
84
+ it 'errors when the given value is not found' do
85
+ assert_raises(Triad::ValueNotPresent){
86
+ triad.keys(Object.new)
87
+ }
88
+ end
89
+ end
90
+
91
+ describe Triad, '#descriptors' do
92
+ let(:user){ Object.new }
93
+ let(:triad){
94
+ tri = Triad.new
95
+ tri << [:admin, 'Admin', user]
96
+ tri
97
+ }
98
+
99
+ it 'returns the descriptor for the given key' do
100
+ assert_equal ['Admin'], triad.descriptors(:admin)
101
+ end
102
+
103
+ it 'returns the descriptor for the given value' do
104
+ assert_equal ['Admin'], triad.descriptors(user)
105
+ end
106
+
107
+ it 'returns the descriptors for the given descriptor' do
108
+ assert_equal ['Admin'], triad.descriptors('Admin')
109
+ end
110
+
111
+ it 'errors when the given descriptor is not found' do
112
+ assert_raises(Triad::DescriptorNotPresent){
113
+ triad.descriptors('Not Present')
114
+ }
115
+ end
116
+
117
+ it 'errors when the given key is not found' do
118
+ assert_raises(Triad::KeyNotPresent){
119
+ triad.descriptors(:invalid_key)
120
+ }
121
+ end
122
+
123
+ it 'errors when the given value is not found' do
124
+ assert_raises(Triad::ValueNotPresent){
125
+ triad.descriptors(Object.new)
126
+ }
127
+ end
128
+ end
129
+
130
+ describe Triad, '#values' do
131
+ let(:user){ Object.new }
132
+ let(:triad){
133
+ tri = Triad.new
134
+ tri << [:admin, 'Admin', user]
135
+ tri
136
+ }
137
+
138
+ it 'returns the value for the given key' do
139
+ assert_equal [user], triad.values(:admin)
140
+ end
141
+
142
+ it 'returns the value for the given descriptor' do
143
+ assert_equal [user], triad.values('Admin')
144
+ end
145
+
146
+ it 'errors when the given key is not found' do
147
+ assert_raises(Triad::KeyNotPresent){
148
+ triad.values(:invalid_key)
149
+ }
150
+ end
151
+
152
+ it 'errors when the given descriptor is not found' do
153
+ assert_raises(Triad::DescriptorNotPresent){
154
+ triad.values('Invalid Descriptor')
155
+ }
156
+ end
157
+ end
158
+
159
+ describe Triad, 'enumeration' do
160
+ let(:user){ Object.new }
161
+ let(:triad){
162
+ tri = Triad.new
163
+ tri << [:admin, 'Admin', user]
164
+ tri
165
+ }
166
+ it 'yields each triad as 3 block variables' do
167
+ result = ''
168
+ triad.each do |key, descriptor, value|
169
+ result << "key: #{key}, descriptor: #{descriptor}, value: #{value.class.name}"
170
+ end
171
+ assert_equal 'key: admin, descriptor: Admin, value: Object', result
172
+ end
173
+ end
data/triad.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'triad/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "triad"
8
+ spec.version = Triad::VERSION
9
+ spec.authors = ["'Jim Gay'"]
10
+ spec.email = ["jim@saturnflyer.com"]
11
+ spec.description = %q{Triad allows you to access data from keys, descriptors, and values}
12
+ spec.summary = %q{Manage a collection with 3 data points}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: triad
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - '''Jim Gay'''
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-19 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
+ description: Triad allows you to access data from keys, descriptors, and values
42
+ email:
43
+ - jim@saturnflyer.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .travis.yml
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - lib/triad.rb
55
+ - lib/triad/version.rb
56
+ - test/test_helper.rb
57
+ - test/triad_test.rb
58
+ - triad.gemspec
59
+ homepage: ''
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.0.3
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Manage a collection with 3 data points
83
+ test_files:
84
+ - test/test_helper.rb
85
+ - test/triad_test.rb
86
+ has_rdoc: