composite 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +44 -0
- data/lib/composite.rb +41 -0
- data/test/test_composite.rb +41 -0
- metadata +48 -0
data/README
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
== Composite version 0.3.0
|
2
|
+
|
3
|
+
=== Overview
|
4
|
+
Mixin module to create classes where the 'whole'
|
5
|
+
object is seen as being composed of 'parts'.
|
6
|
+
Allowing access to some object both as composed
|
7
|
+
as well as in parts. The typical use case is a subclass
|
8
|
+
of String that is used to deal with a string that
|
9
|
+
has a certain format and supports accessor methods
|
10
|
+
to its parts, for example an URI/IRI, a BCP 47 language tag,
|
11
|
+
a name or address in a certain format, and so on.
|
12
|
+
|
13
|
+
=== Usage
|
14
|
+
class myComposite < BaseClass
|
15
|
+
def initialize (n)
|
16
|
+
super(n)
|
17
|
+
end
|
18
|
+
part :part1, :part2, ...
|
19
|
+
def compose
|
20
|
+
# calculate a value for the BaseClass object
|
21
|
+
# from @part1, @part2,...
|
22
|
+
end
|
23
|
+
def decompose
|
24
|
+
# calculate @part1, @part2,...
|
25
|
+
# from the value of BaseClass
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
The above provides methods part1, part1=, part2, part2=,...
|
30
|
+
for access to parts.
|
31
|
+
|
32
|
+
=== Performance
|
33
|
+
decompose is called on each access (both read and write)
|
34
|
+
to any of the parts, because it's impossible to predict
|
35
|
+
when the BaseClass object changes (all methods of the
|
36
|
+
BaseClass would need to be patched). If decompose takes
|
37
|
+
time, it may be possible to speed things up by saving a
|
38
|
+
copy of the BaseClass object, or its hash, internally
|
39
|
+
and do a comparison to see if anything has changed.
|
40
|
+
|
41
|
+
=== Copyright
|
42
|
+
Copyright (c) 2007 Martin J. Du"rst (duerst@it.aoyama.ac.jp)
|
43
|
+
Licensed under the same terms as Ruby. Absolutely no warranty.
|
44
|
+
(see http://www.ruby-lang.org/en/LICENSE.txt)
|
data/lib/composite.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# :include: ../README
|
2
|
+
|
3
|
+
module Composite
|
4
|
+
def self.included(base) #:nodoc:
|
5
|
+
super
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Assumes composite is up to date, and decomposes into parts.
|
10
|
+
# Virtual method, needs to be overwritten where module is included.
|
11
|
+
def decompose; raise NotImplementedError; end
|
12
|
+
# Assumes parts are up to date, and composes from parts.
|
13
|
+
# Virtual method, needs to be overwritten where module is included.
|
14
|
+
def compose; raise NotImplementedError; end
|
15
|
+
|
16
|
+
# Internal module to extend class that includes this module.
|
17
|
+
# This trick of getting around the fact that module methods
|
18
|
+
# aren't inherited when a module is included is from:
|
19
|
+
# http://wiki.rubyonrails.org/rails/pages/SimpleAccessControlExample
|
20
|
+
module ClassMethods
|
21
|
+
# Metaprogramming keyword to define 'part' instance variables
|
22
|
+
# that automatically call compose/decompose on access.
|
23
|
+
def part (*parts, &block)
|
24
|
+
parts.each do |aPart|
|
25
|
+
set_method = (aPart.to_s+'=').to_sym
|
26
|
+
get_method = aPart.to_sym
|
27
|
+
instance = ('@'+aPart.to_s).to_sym
|
28
|
+
send :define_method, get_method do ||
|
29
|
+
decompose
|
30
|
+
instance_variable_get instance
|
31
|
+
end
|
32
|
+
send :define_method, set_method do |a|
|
33
|
+
decompose
|
34
|
+
#call.block
|
35
|
+
instance_variable_set instance, a
|
36
|
+
compose
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# some unit tests for the Composite module
|
2
|
+
# assumes that names are "Given_Name Family_Name",
|
3
|
+
# which is hopelessly non-internationalized, sorry!
|
4
|
+
#
|
5
|
+
# Copyright 2007 Martin J. Du"rst (duerst@it.aoyama.ac.jp);
|
6
|
+
# available under the same licence as Ruby itself
|
7
|
+
# (see http://www.ruby-lang.org/en/LICENSE.txt)
|
8
|
+
|
9
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
10
|
+
require 'Composite'
|
11
|
+
|
12
|
+
class Name < String
|
13
|
+
include Composite
|
14
|
+
def initialize (name)
|
15
|
+
super(name)
|
16
|
+
end
|
17
|
+
part :given, :family
|
18
|
+
def compose
|
19
|
+
replace(@given+' '+@family)
|
20
|
+
end
|
21
|
+
def decompose
|
22
|
+
@given, @family = self.split(' ')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'test/unit'
|
27
|
+
class TestComposite < Test::Unit::TestCase
|
28
|
+
def test_simple
|
29
|
+
n = Name.new('John Smith')
|
30
|
+
assert_equal('John', n.given)
|
31
|
+
assert_equal('Smith', n.family)
|
32
|
+
n.given = 'Jane'
|
33
|
+
assert_equal('Jane Smith', n)
|
34
|
+
n.family = 'Miller'
|
35
|
+
assert_equal('Jane Miller', n)
|
36
|
+
n.given = 'Bill'
|
37
|
+
assert_equal('Bill Miller', n)
|
38
|
+
n.given += '-Willy'
|
39
|
+
assert_equal('Bill-Willy Miller', n)
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: composite
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2007-03-22 00:00:00 +09:00
|
8
|
+
summary: metaprogramming module to (de)compose a base class into/from parts
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: duerst@it.aoyama.ac.jp
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: composite
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Martin J. Du"rst
|
31
|
+
files:
|
32
|
+
- lib/composite.rb
|
33
|
+
- test/test_composite.rb
|
34
|
+
- README
|
35
|
+
test_files:
|
36
|
+
- test/test_composite.rb
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
requirements: []
|
46
|
+
|
47
|
+
dependencies: []
|
48
|
+
|