properties-ruby 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,13 @@
1
+ #
2
+ # Suraj Vijayakumar
3
+ # 19-02-2011
4
+ #
5
+
6
+ #
7
+ # Properties - Provides support to process java style property files.
8
+ #
9
+ module Utils
10
+
11
+ require "utils/properties"
12
+
13
+ end
@@ -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: []