properties-ruby 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/lib/example/example.rb +34 -0
- data/lib/properties-ruby.rb +13 -0
- data/lib/utils/properties.rb +196 -0
- metadata +62 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# Suraj Vijayakumar
|
3
|
+
# 20-02-2011
|
4
|
+
#
|
5
|
+
|
6
|
+
require "properties-ruby"
|
7
|
+
require "time"
|
8
|
+
require "logeasy"
|
9
|
+
|
10
|
+
# Load both the property files.
|
11
|
+
p = Utils::Properties.load_from_file("example.properties", true)
|
12
|
+
Utils::Properties.load_from_file("override.properties", true, p) # Override...
|
13
|
+
|
14
|
+
# Adds the property that was referenced in example.properties.
|
15
|
+
# Since this is not a String, it will not be eligible for evaluation. It will still be used as a reference though.
|
16
|
+
p.add_property("time_now", Time.now)
|
17
|
+
|
18
|
+
# Configuring the root logger so that trace information can be seen.
|
19
|
+
console_appender_2 = LogEasy::ConsoleAppender.new # Simple console appender.
|
20
|
+
console_appender_2.formatter = LogEasy::Appender::FULL_LOGGER_NAME_FORMATTER
|
21
|
+
root_logger = LogEasy::Logger.root_logger # Get the handle to the root logger. The root logger's default level is ALL.
|
22
|
+
root_logger.add_appender(console_appender_2) # Add the appenders to the root logger.
|
23
|
+
root_logger.change_min_level(LogEasy::Level::DEBUG)
|
24
|
+
|
25
|
+
# Access the property values.
|
26
|
+
full_name = p.full_name
|
27
|
+
author = p.author
|
28
|
+
information = p.information
|
29
|
+
|
30
|
+
# Print the information.
|
31
|
+
puts ""
|
32
|
+
puts "App: #{full_name}"
|
33
|
+
puts "Author: #{author}"
|
34
|
+
puts "Built: #{information}"
|
@@ -0,0 +1,196 @@
|
|
1
|
+
#
|
2
|
+
# Suraj Vijayakumar
|
3
|
+
# 19-02-2011
|
4
|
+
#
|
5
|
+
|
6
|
+
require "logeasy"
|
7
|
+
|
8
|
+
module Utils
|
9
|
+
|
10
|
+
# Utility class that provides the ability to load java style properties files. The files can also contain references to any property using the ${key} format.
|
11
|
+
# References are evaluated only when a property's value is requested.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# Load property files.
|
16
|
+
# p = Utils::Properties.load_from_file("example.properties", true)
|
17
|
+
# Utils::Properties.load_from_file("override.properties", true, p) # Override...
|
18
|
+
#
|
19
|
+
# Adds the property that was referenced in example.properties.
|
20
|
+
# Since this is not a String, it will not be eligible for evaluation. It will still be used as a reference though.
|
21
|
+
# p.add_property("time_now", Time.now)
|
22
|
+
#
|
23
|
+
# Configuring the root logger so that trace information can be seen.
|
24
|
+
# console_appender_2 = LogEasy::ConsoleAppender.new # Simple console appender.
|
25
|
+
# console_appender_2.formatter = LogEasy::Appender::FULL_LOGGER_NAME_FORMATTER
|
26
|
+
# root_logger = LogEasy::Logger.root_logger # Get the handle to the root logger. The root logger's default level is ALL.
|
27
|
+
# root_logger.add_appender(console_appender_2) # Add the appenders to the root logger.
|
28
|
+
#
|
29
|
+
# Access the property values.
|
30
|
+
# full_name = p.full_name
|
31
|
+
# author = p.author
|
32
|
+
# information = p.information
|
33
|
+
#
|
34
|
+
# Print the information.
|
35
|
+
# puts "App: #{full_name}"
|
36
|
+
# puts "Author: #{author}"
|
37
|
+
# puts "Built: #{information}"
|
38
|
+
|
39
|
+
class Properties
|
40
|
+
|
41
|
+
@@logger = LogEasy::Logger.get_logger(name)
|
42
|
+
|
43
|
+
# Creates a new Properties object by loading the specified file.
|
44
|
+
# Optionally an existing properties object can be passed in to put the loaded properties into. Existing properties with the same key will be overwritten.
|
45
|
+
# Also the evaluate properties flag can be turned off if it is not required.
|
46
|
+
#
|
47
|
+
# Comments (lines starting with '#') and empty lines are skipped.
|
48
|
+
#
|
49
|
+
# Returns => Properties
|
50
|
+
def Properties.load_from_file(file_path, evaluate_properties = true, existing_properties = Properties.new(evaluate_properties))
|
51
|
+
raise "Properties file not found!" if not File.exists?(file_path)
|
52
|
+
# Read each line, check if it is empty, a comment or starts with an =. If it does then skip it and go to the next line.
|
53
|
+
File.open(file_path, 'r') do |file|
|
54
|
+
line_number = 0
|
55
|
+
file.read.each_line do |line|
|
56
|
+
line.strip!
|
57
|
+
line_number += 1
|
58
|
+
# Skip empty / comment lines.
|
59
|
+
next if (line.length == 0 or line[0] == ?#)
|
60
|
+
# Exception for invalid first character.
|
61
|
+
raise "Invalid property format on line #{line_number}." if line[0] == ?=
|
62
|
+
|
63
|
+
i = line.index("=")
|
64
|
+
if i
|
65
|
+
# Extract the key and value.
|
66
|
+
name = line[0..i - 1].strip
|
67
|
+
value = line[i + 1..-1].strip
|
68
|
+
@@logger.trace("Property '#{name}=#{value} added.")
|
69
|
+
existing_properties.add_property(name, value)
|
70
|
+
else
|
71
|
+
# Not a key-value pair.
|
72
|
+
raise "Invalid property format on line #{line_number}."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
# Return the updated / new properties.
|
77
|
+
existing_properties
|
78
|
+
end
|
79
|
+
|
80
|
+
# Saves a properties value. If a property with this name already exists, it is replaced with this one. Its evaluated flag is also reset.
|
81
|
+
# The name is converted to a Symbol and used as the key.
|
82
|
+
def add_property(name, value)
|
83
|
+
property = Property.new(name, value)
|
84
|
+
key = name.to_sym
|
85
|
+
props[key] = property
|
86
|
+
end
|
87
|
+
|
88
|
+
# Force evaluation of all properties right now.
|
89
|
+
def evaluate_all
|
90
|
+
props.each_key { |key| get(key, true) }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Gets the value (as a String) of a property. The key used must be a Symbol.
|
94
|
+
# If 'force_evaluate' is set to true, the property (and all referenced properties) will be re-evaluated.
|
95
|
+
# If 'evaluate_property' is set to true all nested references will be evaluated even if the global 'evaluate_properties' flag is false.
|
96
|
+
#
|
97
|
+
# Returns => String
|
98
|
+
def get(key, force_evaluate = false, evaluate_property = evaluate_properties)
|
99
|
+
raise "Property '#{key}' not found!" if not props.has_key?(key)
|
100
|
+
# The property exists. Get it. Evaluate it if required.
|
101
|
+
property = props[key]
|
102
|
+
property.evaluate(force_evaluate) do |ref_key|
|
103
|
+
next false if not props.has_key?(ref_key)
|
104
|
+
next get(ref_key, force_evaluate, evaluate_property)
|
105
|
+
end if evaluate_property
|
106
|
+
# Return the value of the fully evaluated property.
|
107
|
+
property.evaluated_value
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# Flag to indicate if properties should be evaluated. This can be overridden on a per property basis in the 'get' method.
|
113
|
+
attr_reader :evaluate_properties
|
114
|
+
attr_reader :props
|
115
|
+
|
116
|
+
# New empty properties.
|
117
|
+
def initialize(evaluate_properties)
|
118
|
+
@evaluate_properties = evaluate_properties
|
119
|
+
@props = Hash.new
|
120
|
+
end
|
121
|
+
|
122
|
+
# Property values can be accessed directly using the name of the property. i.e. p.app_name (where app_name is the name of the property).
|
123
|
+
def method_missing(symbol, *args, &block)
|
124
|
+
# Use 'get' to get the property's value. It will raise an exception if it does not exist.
|
125
|
+
get(symbol, *args)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
# Represents a single property value from a properties file.
|
131
|
+
class Property
|
132
|
+
|
133
|
+
@@logger = LogEasy::Logger.get_logger(name)
|
134
|
+
|
135
|
+
REFERENCE_REGEX = /\${[^}]+}/
|
136
|
+
|
137
|
+
attr_reader :name
|
138
|
+
attr_reader :value
|
139
|
+
attr_reader :evaluated_value
|
140
|
+
|
141
|
+
# Creates a new property.
|
142
|
+
def initialize(name, value)
|
143
|
+
@name = name
|
144
|
+
@value = value
|
145
|
+
@evaluated_value = value
|
146
|
+
@evaluating = false
|
147
|
+
@evaluated = false
|
148
|
+
end
|
149
|
+
|
150
|
+
# Each reference present in this property is passed to the given block. If no block is given the method returns immediately.
|
151
|
+
# The method will return immediately if this property has already been evaluated too.
|
152
|
+
#
|
153
|
+
# If a block is given its result replaces each reference.
|
154
|
+
# A false may be returned to keep the original reference as is.
|
155
|
+
def evaluate(force_evaluate = false)
|
156
|
+
if not force_evaluate and self.evaluated
|
157
|
+
# Property has already been evaluated. Return immediately.
|
158
|
+
# The property has been evaluated. Do not evaluate again.
|
159
|
+
@@logger.fine("Already evaluated '#{name}'.")
|
160
|
+
elsif self.evaluating
|
161
|
+
# The property is currently being evaluated and has been referenced again. Circular reference.
|
162
|
+
raise "Circular reference detected starting at property #{name}=#{value}."
|
163
|
+
elsif block_given?
|
164
|
+
# This property is being evaluated. If a call to evaluate is made while evaluating is true an exception is raised.
|
165
|
+
@@logger.fine("Evaluating '#{name}'...")
|
166
|
+
self.evaluating = true
|
167
|
+
self.evaluated_value = value.gsub(REFERENCE_REGEX) do |match|
|
168
|
+
# Extract the key from the ${key} match and pass it to the block. If there is no block then do nothing.
|
169
|
+
key = match[2..-2].to_sym
|
170
|
+
@@logger.fine("Found reference '#{key}' in '#{name}'.")
|
171
|
+
replacement = yield key
|
172
|
+
# Return the original match as is if the replacement value is false.
|
173
|
+
next match if not replacement
|
174
|
+
# Otherwise return the replacement.
|
175
|
+
@@logger.fine("Replacing '#{key}' in '#{name}' with '#{replacement}'.")
|
176
|
+
next replacement
|
177
|
+
end if value.instance_of?(String) # Only do this for Strings.
|
178
|
+
# The property has been evaluated. Do not evaluate again.
|
179
|
+
@@logger.debug("Final value for '#{name}' is '#{evaluated_value}'.")
|
180
|
+
self.evaluating = false
|
181
|
+
self.evaluated = true
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
protected
|
186
|
+
|
187
|
+
# Flag to indicate that this property is currently being evaluated.
|
188
|
+
attr_accessor :evaluating
|
189
|
+
# Flag to indicate that this property has been fully evaluated.
|
190
|
+
attr_accessor :evaluated
|
191
|
+
# The evaluated value. Calculated by the 'evaluate' method.
|
192
|
+
attr_writer :evaluated_value
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: properties-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Suraj Vijayakumar
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-02-20 00:00:00.000000000 +05:30
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: logeasy
|
17
|
+
requirement: &22772172 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *22772172
|
26
|
+
description: A simple properties file API. Support for Java style properties file.
|
27
|
+
The property files can contain references to other properties using the ${<key_name>}
|
28
|
+
format. Access their values directly using p.prop_name.
|
29
|
+
email: vijayakumar.suraj@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/properties-ruby.rb
|
35
|
+
- lib/utils/properties.rb
|
36
|
+
- lib/example/example.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://rubyforge.org/projects/properties-ruby/
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project: properties-ruby
|
58
|
+
rubygems_version: 1.5.2
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: A simple properties file API.
|
62
|
+
test_files: []
|