yzz 1.0.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 +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/lib/yzz/side.rb +110 -0
- data/lib/yzz/side_pair.rb +51 -0
- data/lib/yzz/version.rb +3 -0
- data/lib/yzz.rb +54 -0
- data/test/yzz_test.rb +78 -0
- data/yzz.gemspec +23 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 86214ab87ff3d7b69aa7dbc97c29abcd49b54d13
|
4
|
+
data.tar.gz: 25f05cecae9791711642b5ca7a8e57db6ffad447
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4eb9074c30c908c2ede65fe40498f680af6780a339f5cae54b2b8d1c83dddba82f242f490b6d93abea4c5e10ca7a0131b222c13836b2ed6857f4320362be4212
|
7
|
+
data.tar.gz: 2c9138c9a46f60259f3bbc443f27c593f51d4a535eb7e77f608f971906e8a90f8a618f9da656e8a0148c22d7b6031221fd1142c61d28fb824d714885a2b24971
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 boris
|
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,30 @@
|
|
1
|
+
# Yzz
|
2
|
+
|
3
|
+
y_ted is a Zz structure domain model
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'yzz'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install yzz
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Zz structures have been described by Ted Nelson. Yzz provides mixin that
|
22
|
+
imbues objects with zz structure qualities.
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
|
26
|
+
1. Fork it
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/yzz/side.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
# Ted Nelson calls zz objects 'cells', and defines posward and negward cell
|
4
|
+
# side in each dimension. This is represented by Side class here, which is
|
5
|
+
# a quadruple [zz object, dimension, direction, neighbor].
|
6
|
+
#
|
7
|
+
class Yzz::Side
|
8
|
+
OPPOSITE = { posward: :negward, negward: :posward }
|
9
|
+
|
10
|
+
attr_reader :zz, :dimension, :direction, :neighbor
|
11
|
+
|
12
|
+
# Standard constructor. 3 compulsory arguments (:zz, :dimension, :direction),
|
13
|
+
# 1 optional argument :neighbor.
|
14
|
+
#
|
15
|
+
def initialize( zz: ( raise ArgumentError, ":zz missing!" ),
|
16
|
+
dimension: ( raise ArgumentError, ":dimension missing!" ),
|
17
|
+
direction: ( raise ArgumentError, ":direction missing!" ),
|
18
|
+
neighbor: nil )
|
19
|
+
raise TypeError, "Wrong :zz type!" unless zz.is_a_zz?
|
20
|
+
@zz, @dimension, @direction = zz, dimension, direction.to_sym
|
21
|
+
raise TypeError, "Direction must be either :posward or :negward!" unless
|
22
|
+
[ :posward, :negward ].include? direction.to_sym
|
23
|
+
set_neighbor! neighbor
|
24
|
+
end
|
25
|
+
|
26
|
+
# Links a new neighbor, unlinking and returning the old one. Cares about
|
27
|
+
# the argument type (Zz descendant or nil required), and has concerns not
|
28
|
+
# to break the new neighbor's conflicting connectivity, if any.
|
29
|
+
#
|
30
|
+
def link new_neighbor
|
31
|
+
return unlink if new_neighbor.nil?
|
32
|
+
raise TypeError, "Zz object or nil expected!" unless new_neighbor.is_a_zz?
|
33
|
+
|
34
|
+
conflicter = opposite_side( of: new_neighbor ).neighbor # have concerns
|
35
|
+
return new_neighbor if conflicter == self # no neighbor change
|
36
|
+
raise TypeError, "Suggested new neighbor (#{new_neighbor}) already " +
|
37
|
+
"has a conflicting #{direction.opposite} link along dimension " +
|
38
|
+
"#{dimension} !" if conflicter.is_a_zz?
|
39
|
+
|
40
|
+
begin # FIXME: This should be an atomic transaction.
|
41
|
+
old_neighbor = set_neighbor! new_neighbor
|
42
|
+
opposite_side( of: new_neighbor ).set_neighbor! zz
|
43
|
+
end
|
44
|
+
return old_neighbor
|
45
|
+
end # def <<
|
46
|
+
alias << link
|
47
|
+
|
48
|
+
# Sets a new neighbor, crossing over the conflicting link, if present, with
|
49
|
+
# the old neighbor.
|
50
|
+
#
|
51
|
+
def crossover new_neighbor
|
52
|
+
return unlink if new_neighbor.nil?
|
53
|
+
raise TypeError, "Zz object or nil expected!" unless new_neighbor.is_a_zz?
|
54
|
+
|
55
|
+
conflicter = opposite_side( of: new_neighbor ).neighbor
|
56
|
+
return new_neighbor if conflicter == self # no neighbor change
|
57
|
+
|
58
|
+
# FIXME: this should be an atomic transaction.
|
59
|
+
begin
|
60
|
+
old_neighbor = set_neighbor! new_neighbor
|
61
|
+
opposite_side( of: new_neighbor ).set_neighbor! zz
|
62
|
+
same_side( of: conflicter ).set_neighbor! old_neighbor # cross over
|
63
|
+
opposite_side( of: old_neighbor ).set_neighbor! conflicter # cross over
|
64
|
+
end
|
65
|
+
return old_neighbor
|
66
|
+
end
|
67
|
+
alias * crossover
|
68
|
+
|
69
|
+
# Returns the string briefly describing the instance.
|
70
|
+
#
|
71
|
+
def to_s
|
72
|
+
"#<YTed::Zz::Side: #{direction} side of #{zz} along #{dimension}>"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Given a zz object (named argument :of), returns its side along same
|
76
|
+
# dimension, in the direction same as self.
|
77
|
+
#
|
78
|
+
def same_side( of: raise( ArgumentError, "Zz object (:of) absent!" ) )
|
79
|
+
of.along( dimension ).send direction
|
80
|
+
end
|
81
|
+
|
82
|
+
# Given a zz object, returns its side along same dimension, in the direction
|
83
|
+
# opposite than self.
|
84
|
+
#
|
85
|
+
def opposite_side( of: zz )
|
86
|
+
of.along( dimension ).send ::Yzz::Side::OPPOSITE[ direction ]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Unlinks the neighbor, returning it.
|
90
|
+
#
|
91
|
+
def unlink
|
92
|
+
unlink!.tap do |neighbor|
|
93
|
+
opposite_side( of: neighbor ).unlink! if neighbor.is_a_zz?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
# Sets neighbor carelessly, returning the old neighbor.
|
100
|
+
#
|
101
|
+
def set_neighbor! new_neighbor
|
102
|
+
neighbor.tap { @neighbor = new_neighbor }
|
103
|
+
end
|
104
|
+
|
105
|
+
# Unlinks the neighbor carelessly, returning it.
|
106
|
+
#
|
107
|
+
def unlink!
|
108
|
+
set_neighbor! nil
|
109
|
+
end
|
110
|
+
end # class YTed::Zz::Side
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
# Represents a pair of Zz::Side instances pertaining to a Zz object along a
|
4
|
+
# particular dimension.
|
5
|
+
#
|
6
|
+
class Yzz::SidePair
|
7
|
+
attr_reader :zz, :dimension, :negward, :posward
|
8
|
+
alias p posward
|
9
|
+
alias n negward
|
10
|
+
|
11
|
+
def initialize( zz: ( raise ArgumentError, ":zz missing!" ),
|
12
|
+
dimension: ( raise ArgumentError, ":dimension missing!" ),
|
13
|
+
negward_neighbor: nil,
|
14
|
+
posward_neighbor: nil )
|
15
|
+
@zz, @dimension = zz, dimension
|
16
|
+
@negward = Yzz::Side.new( zz: zz,
|
17
|
+
dimension: dimension,
|
18
|
+
direction: :negward,
|
19
|
+
neighbor: negward_neighbor )
|
20
|
+
@posward = Yzz::Side.new( zz: zz,
|
21
|
+
dimension: dimension,
|
22
|
+
direction: :posward,
|
23
|
+
neighbor: posward_neighbor )
|
24
|
+
end
|
25
|
+
|
26
|
+
# Links a neighbor posward.
|
27
|
+
#
|
28
|
+
def >> new_neighbor
|
29
|
+
new_neighbor.along( dimension ).tap { posward << new_neighbor }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Crossovers a new neighbor posward.
|
33
|
+
#
|
34
|
+
def * new_neighbor
|
35
|
+
posward * new_neighbor
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns posward neighbor.
|
39
|
+
#
|
40
|
+
def P; posward.neighbor end
|
41
|
+
|
42
|
+
# Returns negward neighbor.
|
43
|
+
#
|
44
|
+
def N; negward.neighbor end
|
45
|
+
|
46
|
+
# Returns the string briefly describing the instance.
|
47
|
+
#
|
48
|
+
def to_s
|
49
|
+
"#<YTed::Zz::SidePair: #{zz} along dimension #{dimension} >"
|
50
|
+
end
|
51
|
+
end # class YTed::Zz::SidePair
|
data/lib/yzz/version.rb
ADDED
data/lib/yzz.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative 'yzz/version'
|
3
|
+
require_relative 'yzz/side'
|
4
|
+
require_relative 'yzz/side_pair'
|
5
|
+
|
6
|
+
# Yzz implements Ted Nelson's zz (hyperorthogonal, Zig-Zag...) structure. It
|
7
|
+
# provides a mixin that imbues objects with zz properties.
|
8
|
+
#
|
9
|
+
# A zz structure consists of zz objects, which exist in multiple dimensions. Zz
|
10
|
+
# objects can be connected by directed edges -- connections. Connected objects
|
11
|
+
# are called neighbors. Each connection belongs to some dimension. A zz object
|
12
|
+
# is considered as having two <em>sides</em> in each dimension: posward side and
|
13
|
+
# negward side. A connection always points away from the posward side, and
|
14
|
+
# towards the neighbor's negward side. In each dimension, zz object can have at
|
15
|
+
# most one posward and one negward neighbor. A zz object can be connected to
|
16
|
+
# itself, forming a loop.
|
17
|
+
#
|
18
|
+
# To these basic properties, Ted Nelson adds a bunch of other terminology.
|
19
|
+
# A rank is a series of zz objects connected along one dimension. A rank viewed
|
20
|
+
# horizontally is referred to as row. A rank viewed vertically is referred to
|
21
|
+
# as column.
|
22
|
+
|
23
|
+
# Mixin defining Zz structure (aka. hyperorthogonal structure). As represented
|
24
|
+
# by YTed::Zz, a Zz structure is a collection of objects, whose connectivity is
|
25
|
+
# defined in a multidimensional space in such way, that each object, along each
|
26
|
+
# dimension, has at most one posward neighbor, and one negward neighbor. The
|
27
|
+
# relation is bijective: If B is a posward neighbor of A along some dimension,
|
28
|
+
# then A must be a negward neighbor of B along that dimension, and vice-versa.
|
29
|
+
#
|
30
|
+
module Yzz
|
31
|
+
# Adds initialization of the @zz_dimensions hash to #initialize.
|
32
|
+
#
|
33
|
+
def initialize *args
|
34
|
+
@zz_dimensions = Hash.new { |ꜧ, missing_dimension|
|
35
|
+
ꜧ[ missing_dimension ] = Yzz::SidePair
|
36
|
+
.new( zz: self, dimension: missing_dimension )
|
37
|
+
} # initialize the @zz_dimensions hash
|
38
|
+
super # and proceed as usual
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a SidePair instance along the requested dimension.
|
42
|
+
#
|
43
|
+
def along dimension
|
44
|
+
@zz_dimensions[ dimension ]
|
45
|
+
end
|
46
|
+
alias call along
|
47
|
+
end
|
48
|
+
|
49
|
+
class Object
|
50
|
+
def is_a_zz?
|
51
|
+
is_a? ::Yzz
|
52
|
+
# class_complies? ::YTed::Zz
|
53
|
+
end
|
54
|
+
end
|
data/test/yzz_test.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
# Until they alias it in the core.
|
8
|
+
require 'active_support/core_ext/string/starts_ends_with'
|
9
|
+
|
10
|
+
require 'yzz' # tested component itself
|
11
|
+
|
12
|
+
describe Yzz do
|
13
|
+
before do
|
14
|
+
@ç = Class.new do
|
15
|
+
include Yzz
|
16
|
+
attr_accessor :value
|
17
|
+
def to_s; "ZzEnabledObject<#{object_id}>" end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "reacts to #is_a_zz?" do
|
22
|
+
assert @ç.new.is_a_zz?
|
23
|
+
# ordinary objets know the method, but return false
|
24
|
+
assert ! Object.new.is_a_zz?
|
25
|
+
end
|
26
|
+
|
27
|
+
it "provides #along instance method" do
|
28
|
+
zz = @ç.new
|
29
|
+
assert_kind_of Yzz::SidePair, zz.along( :row )
|
30
|
+
assert_equal zz.along( :row ), zz.(:row)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'basic zz object behavior' do
|
34
|
+
before do
|
35
|
+
@a = @ç.new
|
36
|
+
end
|
37
|
+
|
38
|
+
it "provides two sides, #opposite_side also tested" do
|
39
|
+
assert_equal @a.(:row).posward, @a.(:row).n.opposite_side
|
40
|
+
assert_equal @a.(:row).negward, @a.(:row).p.opposite_side
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has #to_s" do
|
44
|
+
assert @a.(:row).to_s.starts_with? "#<YTed::Zz::SidePair"
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'more advanced zz object behavior' do
|
48
|
+
it "has #same_side" do
|
49
|
+
zz = @ç.new
|
50
|
+
assert_equal zz.(:row).p, @a.(:row).p.same_side( of: zz )
|
51
|
+
assert_equal zz.(:row).n, @a.(:row).n.same_side( of: zz )
|
52
|
+
end
|
53
|
+
|
54
|
+
it "works" do
|
55
|
+
a, b, c = @ç.new, @ç.new, @ç.new
|
56
|
+
assert ( b.(:row).posward << c ).nil?
|
57
|
+
assert_equal c, b.(:row).P
|
58
|
+
assert_equal b, c.(:row).N
|
59
|
+
assert ( b.(:row).negward << a ).nil?
|
60
|
+
assert_equal a, b.(:row).N
|
61
|
+
assert_equal b, a.(:row).P
|
62
|
+
assert_equal b, c.(:row).negward.unlink
|
63
|
+
assert_equal b, a.(:row).posward.unlink
|
64
|
+
a.(:row) >> b >> c
|
65
|
+
assert_equal b, a.(:row).posward * c
|
66
|
+
assert_equal b, b.(:row) * c
|
67
|
+
assert_equal b, a.(:row).P
|
68
|
+
assert_equal c, b.(:row).P
|
69
|
+
# TODO:
|
70
|
+
# assert_equal [a, c], b.connections.map { |side| side.neighbor }
|
71
|
+
# assert_equal [a, c], b.neighbors
|
72
|
+
# assert_equal [ b.(:row).negward ], b.connections( to: a )
|
73
|
+
# assert_equal [ b.(:row).posward ], b.connections( to: c )
|
74
|
+
# TODO: Rename YTed to Zz
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/yzz.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 'yzz/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "yzz"
|
8
|
+
spec.version = Yzz::VERSION
|
9
|
+
spec.authors = ["boris"]
|
10
|
+
spec.email = ["\"boris@iis.sinica.edu.tw\""]
|
11
|
+
spec.description = %q{A zz structure domain model.}
|
12
|
+
spec.summary = %q{Yzz module is a mixin that imbues object with zz qualities.}
|
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,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yzz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- boris
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-28 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: A zz structure domain model.
|
42
|
+
email:
|
43
|
+
- '"boris@iis.sinica.edu.tw"'
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- lib/yzz.rb
|
54
|
+
- lib/yzz/side.rb
|
55
|
+
- lib/yzz/side_pair.rb
|
56
|
+
- lib/yzz/version.rb
|
57
|
+
- test/yzz_test.rb
|
58
|
+
- yzz.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.0
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Yzz module is a mixin that imbues object with zz qualities.
|
83
|
+
test_files:
|
84
|
+
- test/yzz_test.rb
|