universals 0.0.2
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.
- data/README +69 -0
- data/lib/universals.rb +8 -0
- data/lib/universals/exceptions.rb +40 -0
- data/lib/universals/universe.rb +161 -0
- data/lib/universals/version.rb +11 -0
- data/license.txt +21 -0
- metadata +52 -0
data/README
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
Universals
|
2
|
+
==========
|
3
|
+
Everyone knows that global variables are bad. Sometimes though there are values
|
4
|
+
that need to visible to all aspects of your code. Universals is a library that
|
5
|
+
provides a class that allows for the aggregation of application or library wide
|
6
|
+
data values. The Universe class becomes a centralized location for the storage
|
7
|
+
or retrieval of such values. This avoids the need to use global variables or to
|
8
|
+
pass such values down through the stack to the places they are actually used
|
9
|
+
while avoiding the namespace pollution of global variables.
|
10
|
+
|
11
|
+
Installing The Library
|
12
|
+
----------------------
|
13
|
+
The Universals library is provided as a Ruby gem and thus can be installed with
|
14
|
+
a line such as...
|
15
|
+
|
16
|
+
$> gem install universals
|
17
|
+
|
18
|
+
Using The Library
|
19
|
+
-----------------
|
20
|
+
The library contains a single class called Universe. This class acts very much
|
21
|
+
like a Hash (with a few restrictions). Universe has mixed in Singleton and so
|
22
|
+
there should only ever be one instance of the class that can be accessed using
|
23
|
+
code such as the following...
|
24
|
+
|
25
|
+
Universals::Universe.instance
|
26
|
+
|
27
|
+
The value returned from this call can be treated like a Hash in that values can
|
28
|
+
be set under keys using the array assignment operator like so...
|
29
|
+
|
30
|
+
Universals::Universe.instance["my_value"] = "Blah-de-blah"
|
31
|
+
|
32
|
+
Note that key names must be a String object. In addition, as the class makes the
|
33
|
+
stored values available as properties on the Universe instance (see later for
|
34
|
+
more details), the key must conform to many of the rules for method names. It
|
35
|
+
can only start with a letter (upper or lower case) or an underscore and the
|
36
|
+
remainder of the name must be made up of letters, underscores or numbers. The
|
37
|
+
key may end with either '!' or '?'. Names ending with '=' or containing '[' or
|
38
|
+
']' are explicitly excluded as they would be confusing. If you try to set a
|
39
|
+
value on a Universe instance that does not conform to these rules then you will
|
40
|
+
receive an exception for your trouble.
|
41
|
+
|
42
|
+
As was mention previously, the Universe class makes values stored within it
|
43
|
+
available as properties on the object itself. So, the value set in the previous
|
44
|
+
example could be accessed using code such as...
|
45
|
+
|
46
|
+
Universals::Universe.instance.my_value
|
47
|
+
|
48
|
+
Likewise, values can be set as if they were properties on the object. So, the
|
49
|
+
following are valid assignments...
|
50
|
+
|
51
|
+
Universals::Universe.instance.my_value = 12345
|
52
|
+
Universals::Universe.instance.other_value = "Something else."
|
53
|
+
|
54
|
+
As the Universe class is a singleton, any values assigned into it can be
|
55
|
+
retrieved anywhere. Note, that no effort has been made to make the Universe
|
56
|
+
class thread safe. It is recommended that you assign all of the values needed
|
57
|
+
to the object in a single place and thereafter treat the object as read only
|
58
|
+
if you want to use it in multi-threaded code.
|
59
|
+
|
60
|
+
Deferred Evaluation
|
61
|
+
-------------------
|
62
|
+
If you want to defer the evaluation of a value you can, instead of directly
|
63
|
+
storing the value under it's key, store a Proc that evaluates to the correct
|
64
|
+
value under the key. The next time this key is explicitly fetched from the
|
65
|
+
Universe instance the Proc will be called (with no parameters) and the value
|
66
|
+
it returns will be set under the key instead. Using this technique you can
|
67
|
+
defer the creation of items until they are actually used, allowing them to be
|
68
|
+
created at more appropriate points in the code and avoiding the possible
|
69
|
+
overhead associated with the values creation.
|
data/lib/universals.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c), 2012 Peter Wood
|
4
|
+
# See the license.txt for details of the licensing of the code in this file.
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
|
8
|
+
module Universals
|
9
|
+
# This class provides the exception class used by the Universals library.
|
10
|
+
class UniversalsError < StandardError
|
11
|
+
# Attribute accessor/mutator declarations.
|
12
|
+
attr_accessor :verbose
|
13
|
+
|
14
|
+
# Constructor for the UniversalsError class.
|
15
|
+
#
|
16
|
+
# ==== Parameters
|
17
|
+
# message:: The message to be associated with the error.
|
18
|
+
# cause:: Any underlying exception to be associated with the error.
|
19
|
+
# Defaults to nil.
|
20
|
+
def initialize(message, cause=nil, verbose=true)
|
21
|
+
super(message)
|
22
|
+
@cause = cause
|
23
|
+
@verbose = verbose
|
24
|
+
end
|
25
|
+
|
26
|
+
# This method fetches a stringified interpretation of an exception.
|
27
|
+
def to_s()
|
28
|
+
text = StringIO.new
|
29
|
+
text << super
|
30
|
+
if @verbose
|
31
|
+
text << "\n" + self.backtrace.join("\n")
|
32
|
+
if !@cause.nil?
|
33
|
+
text << "\n\nCause: #{@cause}"
|
34
|
+
text << "\n" + @cause.backtrace.join("\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
text.string
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c), 2012 Peter Wood
|
4
|
+
# See the license.txt for details of the licensing of the code in this file.
|
5
|
+
|
6
|
+
require 'singleton'
|
7
|
+
|
8
|
+
module Universals
|
9
|
+
# The Universals class includes the Ruby Singleton mixin and provides a
|
10
|
+
# single source location to store and retrieve data that is used across
|
11
|
+
# the entirety of an application or libraries code base. This avoids having
|
12
|
+
# to use global variables or to have to pass data elements around. The class
|
13
|
+
# behaves very much like a Hash, mapping keys to values. The class also
|
14
|
+
# makes the values stored within it available as properties, so all values
|
15
|
+
# stored within a Universe must be stored under String keys with names that
|
16
|
+
# conform to standard Ruby method naming criteria.
|
17
|
+
class Universe
|
18
|
+
# Mixin the singleton stuff.
|
19
|
+
include Singleton
|
20
|
+
|
21
|
+
# Mixin the enumerable stuff.
|
22
|
+
include Enumerable
|
23
|
+
|
24
|
+
# Constructor for the Universe class.
|
25
|
+
def initialize
|
26
|
+
@values = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
# This method is used to check whether a property is stored under a given
|
30
|
+
# key within a Universe object.
|
31
|
+
#
|
32
|
+
# ==== Parameters
|
33
|
+
# key:: The key to perform the check for.
|
34
|
+
def has_property?(key)
|
35
|
+
@values.include?(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
# This method fetches the value associated with a given key.
|
39
|
+
#
|
40
|
+
# ==== Parameters
|
41
|
+
# key:: The key for the value to be retrieved.
|
42
|
+
# default:: The default to return if the key does not exist within the
|
43
|
+
# Universe object. Defaults to nil.
|
44
|
+
def get_property(key, default=nil)
|
45
|
+
value = @values.fetch(key, default)
|
46
|
+
if value.respond_to?(:call)
|
47
|
+
value = value.call
|
48
|
+
@values[key] = value
|
49
|
+
end
|
50
|
+
value
|
51
|
+
end
|
52
|
+
|
53
|
+
# This method assigns a value under a specified key within a Universe
|
54
|
+
# object. Existing entries will be overwritten by this method.
|
55
|
+
def set_property(key, value)
|
56
|
+
validate_name(key)
|
57
|
+
@values[key] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
# This method allows multiple values to be set on the Universe object
|
61
|
+
# in a single request.
|
62
|
+
#
|
63
|
+
# ==== Parameters
|
64
|
+
# values:: A Hash of the values to be set on the object. Keys should be
|
65
|
+
# adhere to the standard name requirements for the Universe
|
66
|
+
# object or an exception will be raised. Values specified in
|
67
|
+
# this way will override values already in the object.
|
68
|
+
def set(values={})
|
69
|
+
values.each {|name, value| set_property(name, value)}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Implementation of the each() method for the Universe class.
|
73
|
+
def each(&block)
|
74
|
+
@values.each(&block)
|
75
|
+
end
|
76
|
+
|
77
|
+
# This method fetches a count of the number of items held within an
|
78
|
+
# instance of the Universe class.
|
79
|
+
def size
|
80
|
+
@values.size
|
81
|
+
end
|
82
|
+
|
83
|
+
# This method fetches the key associated with a value stored in the
|
84
|
+
# Universe instance.
|
85
|
+
#
|
86
|
+
# ==== Parameters
|
87
|
+
# value:: The value to retrieve the key for.
|
88
|
+
def key(value)
|
89
|
+
@values.key(value)
|
90
|
+
end
|
91
|
+
|
92
|
+
# This method fetches a collection of the keys stored within a Universe
|
93
|
+
# instance.
|
94
|
+
def keys
|
95
|
+
@values.keys
|
96
|
+
end
|
97
|
+
|
98
|
+
# This method fetches a collection of the values stored within a Universe
|
99
|
+
# instance.
|
100
|
+
def values
|
101
|
+
@values.values
|
102
|
+
end
|
103
|
+
|
104
|
+
# This method deletes all entries from a Universe instance.
|
105
|
+
def clear
|
106
|
+
@values.clear
|
107
|
+
end
|
108
|
+
|
109
|
+
# This method overrides the default respond_to?() method to provide
|
110
|
+
# customer property handling for Universe objects.
|
111
|
+
#
|
112
|
+
# ==== Parameters
|
113
|
+
# name:: The name of the method to perform the check for.
|
114
|
+
def respond_to?(name)
|
115
|
+
@hash.include?(name) || super(name)
|
116
|
+
end
|
117
|
+
|
118
|
+
# This method is invoked whenever a method invocation takes place
|
119
|
+
# against a Universe object but an existing explicit method cannot be
|
120
|
+
# found to meet the call.
|
121
|
+
#
|
122
|
+
# ==== Parameters
|
123
|
+
# name:: The name of the method invoked.
|
124
|
+
# arguments:: A collection of the arguments passed to the method call.
|
125
|
+
# block:: Any block associated with the method call.
|
126
|
+
def method_missing(name, *arguments, &block)
|
127
|
+
if @values.include?(name.to_s)
|
128
|
+
get_property(name.to_s)
|
129
|
+
elsif name.to_s[-1, 1] == "="
|
130
|
+
property = name.to_s
|
131
|
+
property = property[0, property.length - 1]
|
132
|
+
set_property(property, arguments[0])
|
133
|
+
self
|
134
|
+
else
|
135
|
+
super
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Class aliases.
|
140
|
+
alias :[] :get_property
|
141
|
+
alias :[]= :set_property
|
142
|
+
alias :include? :has_property?
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# This method is used internally by the class to determine whether a key
|
147
|
+
# is valid for use with a Universe object.
|
148
|
+
def validate_name(name)
|
149
|
+
if !name.kind_of?(String)
|
150
|
+
raise UniversalsError.new("The key '#{name}' cannot be used in a "\
|
151
|
+
"Universe object as it is not a String.")
|
152
|
+
end
|
153
|
+
|
154
|
+
if /^[a-zA-Z_]+[a-zA-Z_0-9]*[\?!]?$/.match(name).nil?
|
155
|
+
raise UniversalsError.new("The key '#{name}' cannot be used in a "\
|
156
|
+
"Universe object as it is not a valid "\
|
157
|
+
"method name.")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# ! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2012, Peter Wood
|
4
|
+
# See the license.txt for details of the licensing of the code in this file.
|
5
|
+
|
6
|
+
module Universals
|
7
|
+
MAJOR_VERSION = 0
|
8
|
+
MINOR_VERSION = 0
|
9
|
+
BUILD_VERSION = 2
|
10
|
+
VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}.#{BUILD_VERSION}"
|
11
|
+
end
|
data/license.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011 Peter Wood
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: universals
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Black North
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-21 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Universals provides a simple singleton class that can be used to store
|
15
|
+
and retrieve data that is used throughout and application and thereby avoid global
|
16
|
+
variables.
|
17
|
+
email: ruby@blacknorth.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/universals.rb
|
23
|
+
- lib/universals/version.rb
|
24
|
+
- lib/universals/universe.rb
|
25
|
+
- lib/universals/exceptions.rb
|
26
|
+
- license.txt
|
27
|
+
- README
|
28
|
+
homepage: https://github.com/free-beer/Universals
|
29
|
+
licenses: []
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.24
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: A library to provide a source for application wide data.
|
52
|
+
test_files: []
|