composite 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README +44 -0
  2. data/lib/composite.rb +41 -0
  3. data/test/test_composite.rb +41 -0
  4. 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)
@@ -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
+