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.
@@ -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: []