proper_properties 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +104 -0
- data/Rakefile +12 -0
- data/lib/proper_properties/encoding/separators.rb +52 -0
- data/lib/proper_properties/encoding/special_chars.rb +48 -0
- data/lib/proper_properties/encoding/unicode.rb +61 -0
- data/lib/proper_properties/encoding.rb +56 -0
- data/lib/proper_properties/generating/generator.rb +56 -0
- data/lib/proper_properties/generating.rb +1 -0
- data/lib/proper_properties/parsing/normalizer.rb +77 -0
- data/lib/proper_properties/parsing/parser.rb +64 -0
- data/lib/proper_properties/parsing.rb +2 -0
- data/lib/proper_properties/properties.rb +6 -0
- data/lib/proper_properties/version.rb +3 -0
- data/lib/proper_properties.rb +46 -0
- data/proper_properties.gemspec +25 -0
- data/spec/fixtures/test.properties +41 -0
- data/spec/fixtures/test_normalized.properties +14 -0
- data/spec/fixtures/test_out.properties +11 -0
- data/spec/fixtures/test_out_skip_separators.properties +11 -0
- data/spec/fixtures/test_out_skip_special_chars.properties +14 -0
- data/spec/fixtures/test_out_skip_unicode.properties +11 -0
- data/spec/helper.rb +20 -0
- data/spec/proper_properties/encoding/separators_spec.rb +19 -0
- data/spec/proper_properties/encoding/special_chars_spec.rb +23 -0
- data/spec/proper_properties/encoding/unicode_spec.rb +29 -0
- data/spec/proper_properties/encoding_spec.rb +72 -0
- data/spec/proper_properties/generating/generator_spec.rb +47 -0
- data/spec/proper_properties/parsing/normalizer_spec.rb +13 -0
- data/spec/proper_properties/parsing/parser_spec.rb +36 -0
- data/spec/proper_properties/version_spec.rb +7 -0
- data/spec/proper_properties_spec.rb +43 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b0e73ae3fb455d335998b9ced5a388d03e923384
|
4
|
+
data.tar.gz: 174890d5265606617411593f037279ef2bbc9c81
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b402ae7a76d56183cf457ce71e97ce8f5f68dae4fd64afecb130abdfcf7aa493214a2bc65d56138f48991bd8193643bd2826953c1a22cf7d11134a7b3cc9213e
|
7
|
+
data.tar.gz: 711cf90f60b7ee205cfe3f921155b3ae3b0fdfb8545b3e886d8a5e717ab2cb62d48a81105ec2afe6ad176ade4e9ce300f6de8b2bbc3b156cd05568b071e7c778
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2014 Jonas Thiel (Applies to code available as https://github.com/jnbt/java-properties 1f2c4b008d69d0eae1084b1adfdea814e2b29899)
|
2
|
+
Copyright (c) 2014 tnarik (Modifications in https://github.com/tnarik/proper_properties)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# ProperProperties
|
2
|
+
|
3
|
+
[![Build Status](http://img.shields.io/travis/tnarik/proper_properties.svg)](https://travis-ci.org/tnarik/proper_properties)
|
4
|
+
[![Code Climate](http://img.shields.io/codeclimate/github/tnarik/proper_properties.svg)](https://codeclimate.com/github/tnarik/proper_properties)
|
5
|
+
[![Coveralls](http://img.shields.io/coveralls/tnarik/proper_properties.svg)](https://coveralls.io/r/tnarik/proper_properties)
|
6
|
+
[![RubyGems](http://img.shields.io/gem/v/proper_properties.svg)](http://rubygems.org/gems/proper_properties)
|
7
|
+
[![Gemnasium](http://img.shields.io/gemnasium/tnarik/proper_properties.svg)](https://gemnasium.com/tnarik/proper_properties)
|
8
|
+
|
9
|
+
A ruby library to read and write [Java properties files](http://en.wikipedia.org/wiki/.properties), which format is better describe [in the Java documentation](http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader\)).
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Install via Rubygems or Gemfile
|
14
|
+
|
15
|
+
```zsh
|
16
|
+
$ gem install proper_properties
|
17
|
+
```
|
18
|
+
|
19
|
+
## Loading files
|
20
|
+
|
21
|
+
You can load a valid Java properties file from the file system using a path:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
properties = ProperProperties.load("path/to/my.properties")
|
25
|
+
properties[:foo] # => "bar"
|
26
|
+
```
|
27
|
+
|
28
|
+
If have already the content of the properties file at hand than parse the content as:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
properties = ProperProperties.load("foo=bar")
|
32
|
+
properties[:foo] # => "bar"
|
33
|
+
```
|
34
|
+
|
35
|
+
## Writing files
|
36
|
+
|
37
|
+
You can write any Hash-like structure as a properties file:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
hash = {:foo => "bar"}
|
41
|
+
ProperProperties.write(hash, "path/to/my.properties")
|
42
|
+
```
|
43
|
+
|
44
|
+
Or if you want to omit the file you can receive the content directly:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
hash = {:foo => "bar"}
|
48
|
+
ProperProperties.generate(hash) # => "foo=bar"
|
49
|
+
```
|
50
|
+
|
51
|
+
## Encodings and special chars
|
52
|
+
|
53
|
+
Although ISO 8859-1 is assumed for Java properties files, they normally use UTF-8 encoding. This tool tries to convert them:
|
54
|
+
|
55
|
+
```
|
56
|
+
"ה" <=> "\u05d4"
|
57
|
+
```
|
58
|
+
|
59
|
+
The tool also escaped every '=', ' ' and ':' in the name part of a property line:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
ProperProperties.generate({"i : like=strange" => "bar"})
|
63
|
+
# => "i\ \:\ like\=strange=bar"
|
64
|
+
```
|
65
|
+
|
66
|
+
## Multi line and line breaks
|
67
|
+
|
68
|
+
In Java properties files there is distinction between natural lines and logical lines (than may span several lines by escaping the line terminator characters).
|
69
|
+
|
70
|
+
Assume the following input:
|
71
|
+
|
72
|
+
```ini
|
73
|
+
my=This is a multi \
|
74
|
+
line content with only \n one line break
|
75
|
+
```
|
76
|
+
|
77
|
+
The parses would read:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
{:my => "This is a multi line content which only \n one line break"}
|
81
|
+
```
|
82
|
+
|
83
|
+
In the opposite direction line breaks will be correctly escaped but the generator will never use multi line values.
|
84
|
+
|
85
|
+
## Contributing
|
86
|
+
|
87
|
+
1. [Fork it!](https://github.com/tnarik/proper_properties/fork)
|
88
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
89
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
90
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
91
|
+
5. Create new Pull Request
|
92
|
+
|
93
|
+
## Author
|
94
|
+
|
95
|
+
- Tnarik Innael (@tnarik)
|
96
|
+
- Jonas Thiel (@jonasthiel) : [original project](https://github.com/jnbt/java-properties) from commit [1f2c4b008d69d0eae1084b1adfdea814e2b29899]
|
97
|
+
|
98
|
+
## References
|
99
|
+
|
100
|
+
For a proper description about the properties file format have a look at the [Java Plattform documentation](http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader\)).
|
101
|
+
|
102
|
+
## License
|
103
|
+
|
104
|
+
This gem is released under the MIT License. See the LICENSE.txt file for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module ProperProperties
|
2
|
+
module Encoding
|
3
|
+
# Module to escape separators as : or =
|
4
|
+
# @see ProperProperties::Encoding
|
5
|
+
module Separators
|
6
|
+
|
7
|
+
# Marker for all separators
|
8
|
+
# @return [Regexp]
|
9
|
+
ENCODE_SEPARATOR_MARKER = /[ :=]/
|
10
|
+
|
11
|
+
# Marker for already escaped separators
|
12
|
+
# @return [Regexp]
|
13
|
+
ESCAPING_MARKER = /\\/
|
14
|
+
|
15
|
+
# Char to use for escaping
|
16
|
+
# @return [String]
|
17
|
+
ESCAPE = "\\"
|
18
|
+
|
19
|
+
# Marker for all escaped separators
|
20
|
+
# @return [Regexp]
|
21
|
+
DECODE_SEPARATOR_MARKER = /\\([ :=])/
|
22
|
+
|
23
|
+
# Escapes all not already escaped separators
|
24
|
+
# @param text [text]
|
25
|
+
# @return [String] The escaped text for chaining
|
26
|
+
def self.encode!(text)
|
27
|
+
buffer = StringIO.new
|
28
|
+
last_token = ''
|
29
|
+
text.each_char do |char|
|
30
|
+
if char =~ ENCODE_SEPARATOR_MARKER && last_token !~ ESCAPING_MARKER
|
31
|
+
buffer << ESCAPE
|
32
|
+
end
|
33
|
+
buffer << char
|
34
|
+
last_token = char
|
35
|
+
end
|
36
|
+
text.replace buffer.string
|
37
|
+
text
|
38
|
+
end
|
39
|
+
|
40
|
+
# Removes escapes from escaped separators
|
41
|
+
# @param text [text]
|
42
|
+
# @return [String] The unescaped text for chaining
|
43
|
+
def self.decode!(text)
|
44
|
+
text.gsub!(DECODE_SEPARATOR_MARKER) do
|
45
|
+
$1
|
46
|
+
end
|
47
|
+
text
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ProperProperties
|
2
|
+
module Encoding
|
3
|
+
# Module to escape and unescape special chars
|
4
|
+
# @see ProperProperties::Encoding
|
5
|
+
module SpecialChars
|
6
|
+
|
7
|
+
# Lookup table for escaping special chars
|
8
|
+
# @return [Hash]
|
9
|
+
ESCAPING = {
|
10
|
+
"\t" => '\\t',
|
11
|
+
"\r" => '\\r',
|
12
|
+
"\n" => '\\n',
|
13
|
+
"\f" => '\\f'
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
# Lookup table to remove escaping from special chars
|
17
|
+
# @return [Hash]
|
18
|
+
DESCAPING = ESCAPING.invert.freeze
|
19
|
+
|
20
|
+
# Marks a segment which has is an encoding special char
|
21
|
+
# @return [Regexp]
|
22
|
+
DESCAPING_MARKER = /\\./
|
23
|
+
|
24
|
+
# Encodes the content a text by escaping all special chars
|
25
|
+
# @param text [String]
|
26
|
+
# @return [String] The escaped text for chaining
|
27
|
+
def self.encode!(text)
|
28
|
+
buffer = StringIO.new
|
29
|
+
text.each_char do |char|
|
30
|
+
buffer << ESCAPING.fetch(char, char)
|
31
|
+
end
|
32
|
+
text.replace buffer.string
|
33
|
+
text
|
34
|
+
end
|
35
|
+
|
36
|
+
# Decodes the content a text by removing all escaping from special chars
|
37
|
+
# @param text [String]
|
38
|
+
# @return [String] The unescaped text for chaining
|
39
|
+
def self.decode!(text)
|
40
|
+
text.gsub!(DESCAPING_MARKER) do |match|
|
41
|
+
DESCAPING.fetch(match, match)
|
42
|
+
end
|
43
|
+
text
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ProperProperties
|
2
|
+
module Encoding
|
3
|
+
# Module to encode and decode unicode chars
|
4
|
+
# @see ProperProperties::Encoding
|
5
|
+
module Unicode
|
6
|
+
|
7
|
+
# Marker for encoded unicode chars
|
8
|
+
# @return [Regexp]
|
9
|
+
UNICODE_MARKER = /\\[uU]([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})/
|
10
|
+
|
11
|
+
# Escape char for unicode chars
|
12
|
+
# @return [String]
|
13
|
+
UNICODE_ESCAPE = "\\u"
|
14
|
+
|
15
|
+
# Decodes all unicode chars from escape sequences in place
|
16
|
+
# @param text [String]
|
17
|
+
# @return [String] The encoded text for chaining
|
18
|
+
def self.decode!(text)
|
19
|
+
text.gsub!(UNICODE_MARKER) do
|
20
|
+
unicode($1.hex)
|
21
|
+
end
|
22
|
+
text
|
23
|
+
end
|
24
|
+
|
25
|
+
# Decodes all unicode chars into escape sequences in place
|
26
|
+
# @param text [String]
|
27
|
+
# @return [String] The decoded text for chaining
|
28
|
+
def self.encode!(text)
|
29
|
+
buffer = StringIO.new
|
30
|
+
text.each_char do |char|
|
31
|
+
if char.ascii_only?
|
32
|
+
buffer << char
|
33
|
+
else
|
34
|
+
buffer << UNICODE_ESCAPE
|
35
|
+
buffer << hex(char.codepoints.first)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
text.replace buffer.string
|
39
|
+
text
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def self.unicode(code)
|
45
|
+
[code].pack("U")
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.hex(codepoint)
|
49
|
+
hex = codepoint.to_s(16)
|
50
|
+
size = hex.size
|
51
|
+
# padding the hex value for uneven digest
|
52
|
+
if (size % 2) == 1
|
53
|
+
"0#{hex}"
|
54
|
+
else
|
55
|
+
hex
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'proper_properties/encoding/special_chars'
|
2
|
+
require 'proper_properties/encoding/separators'
|
3
|
+
require 'proper_properties/encoding/unicode'
|
4
|
+
|
5
|
+
module ProperProperties
|
6
|
+
# Module to encode and decode
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
# encoded = Encoding.encode!("Some text to be encoded")
|
10
|
+
# decoded = Encoding.decode!("Some text to be decoded")
|
11
|
+
#
|
12
|
+
# You can disable separate encoding (and decoding) steps,
|
13
|
+
# by passing in additional flags:
|
14
|
+
#
|
15
|
+
# * SKIP_SEPARATORS: Do not code the separators (space,:,=)
|
16
|
+
# * SKIP_UNICODE: Do not code unicode chars
|
17
|
+
# * SKIP_SPECIAL_CHARS: Do not code newlines, tab stops, ...
|
18
|
+
#
|
19
|
+
module Encoding
|
20
|
+
|
21
|
+
# Flag for skipping separators encodings / decoding
|
22
|
+
# @return [Symbol]
|
23
|
+
SKIP_SEPARATORS=:skip_separators
|
24
|
+
|
25
|
+
# Flag for skipping separators encodings / decoding
|
26
|
+
# @return [Symbol]
|
27
|
+
SKIP_UNICODE=:skip_unicode
|
28
|
+
|
29
|
+
# Flag for skipping separators encodings / decoding
|
30
|
+
# @return [Symbol]
|
31
|
+
SKIP_SPECIAL_CHARS=:skip_special_chars
|
32
|
+
|
33
|
+
# Encode a given text in place
|
34
|
+
# @param text [String]
|
35
|
+
# @param *flags [Array] Optional flags to skip encoding steps
|
36
|
+
# @return [String] The encoded text for chaining
|
37
|
+
def self.encode!(text, *flags)
|
38
|
+
SpecialChars.encode!(text) unless flags.include?(SKIP_SPECIAL_CHARS)
|
39
|
+
Separators.encode!(text) unless flags.include?(SKIP_SEPARATORS)
|
40
|
+
Unicode.encode!(text) unless flags.include?(SKIP_UNICODE)
|
41
|
+
text
|
42
|
+
end
|
43
|
+
|
44
|
+
# Decodes a given text in place
|
45
|
+
# @param text [String]
|
46
|
+
# @param *flags [Array] Optional flags to skip decoding steps
|
47
|
+
# @return [String] The decoded text for chaining
|
48
|
+
def self.decode!(text, *flags)
|
49
|
+
Unicode.decode!(text) unless flags.include?(SKIP_UNICODE)
|
50
|
+
Separators.decode!(text) unless flags.include?(SKIP_SEPARATORS)
|
51
|
+
SpecialChars.decode!(text) unless flags.include?(SKIP_SPECIAL_CHARS)
|
52
|
+
text
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ProperProperties
|
2
|
+
module Generating
|
3
|
+
# This module allows generating the content of a properties file
|
4
|
+
# base on a {Properties} object (or any other hash like structure)
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Generator.generate({:item => "something ה"}) => "item=something \u05d4"
|
8
|
+
#
|
9
|
+
module Generator
|
10
|
+
# Character used for key-value separation
|
11
|
+
# @return [String]
|
12
|
+
KEY_VALUE_SEPARATOR = '='
|
13
|
+
|
14
|
+
# Default options
|
15
|
+
# @return [Hash]
|
16
|
+
DEFAULT_OPTIONS = {
|
17
|
+
:skip_encode_unicode => false,
|
18
|
+
:skip_encode_separators => false,
|
19
|
+
:skip_encode_special_chars => false
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# Generates a properties file content based on a hash
|
23
|
+
# @param properties [Properties] or simple hash
|
24
|
+
# @param options [Hash]
|
25
|
+
# @option options skip_encode_unicode [Boolean] Skip unicode encoding
|
26
|
+
# @option options skip_encode_separators [Boolean] Skip seperators encoding
|
27
|
+
# @option options skip_encode_special_chars [Boolean] Skip special char encoding
|
28
|
+
# @return [String]
|
29
|
+
def self.generate(properties, options = {})
|
30
|
+
options = DEFAULT_OPTIONS.merge(options)
|
31
|
+
lines = []
|
32
|
+
properties.each do |key, value|
|
33
|
+
lines << build_line(key, value, options)
|
34
|
+
end
|
35
|
+
lines.join("\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.build_line(key, value, options)
|
41
|
+
encoded_key = Encoding.encode!(key.to_s.dup, *encoding_skips(false, options))
|
42
|
+
encoded_value = Encoding.encode!(value.to_s.dup, *encoding_skips(true, options))
|
43
|
+
|
44
|
+
encoded_key + KEY_VALUE_SEPARATOR + encoded_value
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.encoding_skips(is_value, options)
|
48
|
+
skips = []
|
49
|
+
skips << Encoding::SKIP_SEPARATORS if is_value || options[:skip_encode_separators]
|
50
|
+
skips << Encoding::SKIP_UNICODE if options[:skip_encode_unicode]
|
51
|
+
skips << Encoding::SKIP_SPECIAL_CHARS if options[:skip_encode_special_chars]
|
52
|
+
skips
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'proper_properties/generating/generator'
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module ProperProperties
|
2
|
+
module Parsing
|
3
|
+
# Module to normalize the content of a properties file
|
4
|
+
#
|
5
|
+
# @example Normalizes:
|
6
|
+
# # Comment 1
|
7
|
+
# ! Comment 2
|
8
|
+
# item0
|
9
|
+
# item1 = item1
|
10
|
+
# item2 : item2
|
11
|
+
# item3=line 1 \
|
12
|
+
# line 2
|
13
|
+
#
|
14
|
+
# @example Into:
|
15
|
+
#
|
16
|
+
# item0
|
17
|
+
# item1=item1
|
18
|
+
# item2=item2
|
19
|
+
# item3=line 1 line 2
|
20
|
+
#
|
21
|
+
module Normalizer
|
22
|
+
|
23
|
+
# Describes a single normalization rule by replacing content
|
24
|
+
class Rule
|
25
|
+
# Initializes a new rules base on a matching regexp
|
26
|
+
# and a replacement as substitution
|
27
|
+
# @param matcher [Regexp]
|
28
|
+
# @param replacement [String]
|
29
|
+
def initialize(matcher, replacement = '')
|
30
|
+
@matcher = matcher
|
31
|
+
@replacement = replacement
|
32
|
+
end
|
33
|
+
|
34
|
+
# Apply the substitution to the text in place
|
35
|
+
# @param text [string]
|
36
|
+
# @return [String]
|
37
|
+
def apply!(text)
|
38
|
+
text.gsub!(@matcher, @replacement)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Collection of ordered rules
|
43
|
+
RULES = []
|
44
|
+
|
45
|
+
# Removes leading whitespace
|
46
|
+
RULES << Rule.new(/^\s+/)
|
47
|
+
|
48
|
+
# Strings ending with \ are concatenated (only if the number is odd)
|
49
|
+
RULES << Rule.new(/^(.*[^\\]((\\){2})*)\\$\s+/, '\1')
|
50
|
+
|
51
|
+
# Removes comments (after the application of the logic line concatenation)
|
52
|
+
RULES << Rule.new(/^\s*[!\#].*$/)
|
53
|
+
|
54
|
+
# Removes empty lines
|
55
|
+
RULES << Rule.new(/^$(\r\n?|\n)/)
|
56
|
+
|
57
|
+
# Unescape double backslashes
|
58
|
+
RULES << Rule.new(/\\\\/, '\\')
|
59
|
+
|
60
|
+
# Remove whitespace around delimiters and replace with =
|
61
|
+
RULES << Rule.new(/^((?:(?:\\[=: \t])|[^=: \t])+)[ \t]*[=: \t][ \t]*/, '\1=')
|
62
|
+
|
63
|
+
RULES.freeze
|
64
|
+
|
65
|
+
# Normalizes the content of a properties file content by applying the RULES
|
66
|
+
# @param text [String]
|
67
|
+
# @return [String]
|
68
|
+
def self.normalize!(text)
|
69
|
+
RULES.each do |rule|
|
70
|
+
rule.apply!(text)
|
71
|
+
end
|
72
|
+
text
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module ProperProperties
|
3
|
+
module Parsing
|
4
|
+
# This module allows parsing of a properties file content string
|
5
|
+
# into a {Properties} object
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# Parser.parse("item=something \u05d4") => {:item => "something ה"}
|
9
|
+
#
|
10
|
+
module Parser
|
11
|
+
|
12
|
+
# Symbol which separates key from value after normalization
|
13
|
+
# @return [String]
|
14
|
+
KEY_VALUE_MARKER = '='
|
15
|
+
|
16
|
+
# Symbol which escapes a KEY_VALUE_MARKER in the key name
|
17
|
+
# @return [String]
|
18
|
+
KEY_ESCAPE = '\\'
|
19
|
+
|
20
|
+
# Marker for a line which only consists of an key w/o value
|
21
|
+
# @return [Regexp]
|
22
|
+
KEY_ONLY_MARKER = /^(\S+)$/
|
23
|
+
|
24
|
+
# Parses a string into a {Properties} object
|
25
|
+
# @param text [String]
|
26
|
+
# @return [Properties]
|
27
|
+
def self.parse(text)
|
28
|
+
properties = Properties.new
|
29
|
+
Normalizer.normalize!(text)
|
30
|
+
text.each_line do |line|
|
31
|
+
key, value = extract_key_and_value(line.chomp)
|
32
|
+
append_to_properties(properties, key, value)
|
33
|
+
end
|
34
|
+
properties
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.extract_key_and_value(line)
|
40
|
+
# A line must be handled char by char to handled escaped '=' chars in the key name
|
41
|
+
key = StringIO.new
|
42
|
+
value = StringIO.new
|
43
|
+
key_complete = false
|
44
|
+
last_token = ''
|
45
|
+
line.each_char do |char|
|
46
|
+
if !key_complete && char == KEY_VALUE_MARKER && last_token != KEY_ESCAPE
|
47
|
+
key_complete = true
|
48
|
+
else
|
49
|
+
(key_complete ? value : key) << char
|
50
|
+
end
|
51
|
+
last_token = char
|
52
|
+
end
|
53
|
+
[key.string, value.string]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.append_to_properties(properties, key, value)
|
57
|
+
unless key.nil? && value.nil?
|
58
|
+
properties[Encoding.decode!(key).to_sym] = Encoding.decode!(value, Encoding::SKIP_SEPARATORS)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'proper_properties/version'
|
2
|
+
require 'proper_properties/properties'
|
3
|
+
require 'proper_properties/encoding'
|
4
|
+
require 'proper_properties/parsing'
|
5
|
+
require 'proper_properties/generating'
|
6
|
+
|
7
|
+
# A module to read and write Proper properties files
|
8
|
+
module ProperProperties
|
9
|
+
|
10
|
+
# Parses the content of a Proper properties file
|
11
|
+
# @see Parsing::Parser
|
12
|
+
# @param text [String]
|
13
|
+
# @return [Properties]
|
14
|
+
def self.parse(text)
|
15
|
+
Parsing::Parser.parse(text)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Generates the content of a Proper properties file
|
19
|
+
# @see Generating::Generator
|
20
|
+
# @param hash [Hash]
|
21
|
+
# @param options [Hash] options for the generator
|
22
|
+
# @return [String]
|
23
|
+
def self.generate(hash, options = {})
|
24
|
+
Generating::Generator.generate(hash, options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Loads and parses a Proper properties file
|
28
|
+
# @see Parsing::Parser
|
29
|
+
# @param path [String]
|
30
|
+
# @param encoding [String]
|
31
|
+
# @param allow_invalid_byte_sequence [Boolean]
|
32
|
+
# @return [Properties]
|
33
|
+
def self.load(path, encoding = 'UTF-8', allow_invalid_byte_sequence = true)
|
34
|
+
parse(File.read(path).encode(encoding, 'binary', allow_invalid_byte_sequence ? {invalid: :replace, undef: :replace} : {} ))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generates a Proper properties file
|
38
|
+
# @see Generating::Generator
|
39
|
+
# @param hash [Hash]
|
40
|
+
# @param path [String]
|
41
|
+
# @param options [Hash] options for the generator
|
42
|
+
def self.write(hash, path, options = {})
|
43
|
+
File.write(path, generate(hash, options))
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'proper_properties/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "proper_properties"
|
8
|
+
spec.version = ProperProperties::VERSION
|
9
|
+
spec.authors = ["Tnarik Innael"]
|
10
|
+
spec.email = ["tnarik@lecafeautomatique.co.uk"]
|
11
|
+
spec.summary = %q{Loader and writer for Java properties files}
|
12
|
+
spec.description = %q{Library for loading and writing of Java properties files that matches java.util.Properties behaviour}
|
13
|
+
spec.homepage = "https://github.com/tnarik/proper_properties"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# development dependencies
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'coveralls'
|
23
|
+
spec.add_development_dependency 'simplecov'
|
24
|
+
spec.add_development_dependency 'minitest'
|
25
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Comment 1
|
2
|
+
! Comment 2
|
3
|
+
item0
|
4
|
+
item1 = item1
|
5
|
+
item2 : item2
|
6
|
+
item3 item3
|
7
|
+
|
8
|
+
#Comment 3
|
9
|
+
! Comment 4
|
10
|
+
|
11
|
+
it\ em4=item4
|
12
|
+
it\=em5:item5
|
13
|
+
item6 item6
|
14
|
+
|
15
|
+
!Comment 5
|
16
|
+
# Comment 6
|
17
|
+
|
18
|
+
item7 = line 1 \
|
19
|
+
line 2 \
|
20
|
+
line 3
|
21
|
+
|
22
|
+
item8 : line 1 \
|
23
|
+
#Not a Comment \
|
24
|
+
line 2 \
|
25
|
+
line 3
|
26
|
+
|
27
|
+
item9 line 1 \
|
28
|
+
line 2 \
|
29
|
+
line 3
|
30
|
+
|
31
|
+
item10=test\n\ttest\u0050 \
|
32
|
+
test\n\ttest \
|
33
|
+
test\n\ttest = test
|
34
|
+
|
35
|
+
item11 : line 1 \\\
|
36
|
+
line 2 \\\\\
|
37
|
+
line 3 \
|
38
|
+
line 4
|
39
|
+
|
40
|
+
item12 : line 1\\
|
41
|
+
item13 : line 1
|
@@ -0,0 +1,14 @@
|
|
1
|
+
item0
|
2
|
+
item1=item1
|
3
|
+
item2=item2
|
4
|
+
item3=item3
|
5
|
+
it\ em4=item4
|
6
|
+
it\=em5=item5
|
7
|
+
item6=item6
|
8
|
+
item7=line 1 line 2 line 3
|
9
|
+
item8=line 1 #Not a Comment line 2 line 3
|
10
|
+
item9=line 1 line 2 line 3
|
11
|
+
item10=test\n\ttest\u0050 test\n\ttest test\n\ttest = test
|
12
|
+
item11=line 1 \line 2 \\line 3 line 4
|
13
|
+
item12=line 1\
|
14
|
+
item13=line 1
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
Coveralls::SimpleCov::Formatter,
|
6
|
+
SimpleCov::Formatter::HTMLFormatter
|
7
|
+
]
|
8
|
+
|
9
|
+
SimpleCov.start
|
10
|
+
|
11
|
+
require 'minitest/autorun'
|
12
|
+
require 'proper_properties'
|
13
|
+
|
14
|
+
class Minitest::Spec
|
15
|
+
|
16
|
+
def fixture(*segments)
|
17
|
+
File.read(File.join(File.dirname(__FILE__), "fixtures", *segments))
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe ProperProperties::Encoding::Separators do
|
4
|
+
subject{ ProperProperties::Encoding::Separators }
|
5
|
+
let(:raw) { 'this is some = text : with special \\=separators' }
|
6
|
+
let(:raw_normalizd) { 'this is some = text : with special =separators' }
|
7
|
+
let(:encoded){ 'this\\ is\\ some\\ \\=\\ text\\ \\:\\ with\\ special\\ \\=separators' }
|
8
|
+
|
9
|
+
it "encodes separators" do
|
10
|
+
processed = subject.encode!(raw.dup)
|
11
|
+
processed.must_equal encoded
|
12
|
+
end
|
13
|
+
|
14
|
+
it "decodes separators" do
|
15
|
+
processed = subject.decode!(encoded.dup)
|
16
|
+
processed.must_equal raw_normalizd
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe ProperProperties::Encoding::SpecialChars do
|
4
|
+
subject{ ProperProperties::Encoding::SpecialChars }
|
5
|
+
let(:raw) { "this is some \n text \t with special\r chars\f" }
|
6
|
+
let(:encoded){ 'this is some \n text \t with special\r chars\f' }
|
7
|
+
|
8
|
+
it "encodes special chars" do
|
9
|
+
processed = subject.encode!(raw.dup)
|
10
|
+
processed.must_equal encoded
|
11
|
+
end
|
12
|
+
|
13
|
+
it "deencodes special chars" do
|
14
|
+
processed = subject.decode!(encoded.dup)
|
15
|
+
processed.must_equal raw
|
16
|
+
end
|
17
|
+
|
18
|
+
it "decodes and encodes to the same" do
|
19
|
+
encoded = subject.encode!(raw.dup)
|
20
|
+
deconded = subject.decode!(encoded)
|
21
|
+
deconded.must_equal raw
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe ProperProperties::Encoding::Unicode do
|
5
|
+
subject{ ProperProperties::Encoding::Unicode }
|
6
|
+
|
7
|
+
let(:encoded) { 'this is some \u0024 text \U05D4 with unicode' }
|
8
|
+
let(:encoded_normalized) { 'this is some $ text \u05d4 with unicode' }
|
9
|
+
let(:decoded) { 'this is some $ text ה with unicode' }
|
10
|
+
|
11
|
+
it "decodes unicode chars" do
|
12
|
+
subject.decode!(encoded.dup).must_equal decoded
|
13
|
+
end
|
14
|
+
|
15
|
+
it "encodes unicode chars" do
|
16
|
+
subject.encode!(decoded.dup).must_equal encoded_normalized
|
17
|
+
end
|
18
|
+
|
19
|
+
it "encodes unicode chars but has 2-based hex size" do
|
20
|
+
subject.encode!("ה").must_equal '\u05d4'
|
21
|
+
subject.encode!("ᘓ").must_equal '\u1613'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "decodes and encodes" do
|
25
|
+
encoded = subject.encode!(decoded.dup)
|
26
|
+
deconded = subject.decode!(encoded.dup)
|
27
|
+
deconded.must_equal decoded
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe ProperProperties::Encoding do
|
5
|
+
subject{ ProperProperties::Encoding }
|
6
|
+
|
7
|
+
describe "full" do
|
8
|
+
let(:decoded){ "this is some \n text = with ה" }
|
9
|
+
let(:encoded){ 'this\ is\ some\ \n\ text\ \=\ with\ \u05d4' }
|
10
|
+
|
11
|
+
it "encodes correctly" do
|
12
|
+
input = decoded.dup
|
13
|
+
processed = subject.encode!(input)
|
14
|
+
processed.must_equal encoded
|
15
|
+
end
|
16
|
+
|
17
|
+
it "decodes correctly" do
|
18
|
+
input = encoded.dup
|
19
|
+
processed = subject.decode!(input)
|
20
|
+
processed.must_equal decoded
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "skip_separators" do
|
25
|
+
let(:decoded){ "this is some \n text = with ה" }
|
26
|
+
let(:encoded){ 'this is some \n text = with \u05d4' }
|
27
|
+
|
28
|
+
it "encodes correctly" do
|
29
|
+
input = decoded.dup
|
30
|
+
processed = subject.encode!(input, subject::SKIP_SEPARATORS)
|
31
|
+
processed.must_equal encoded
|
32
|
+
end
|
33
|
+
|
34
|
+
it "decodes correctly" do
|
35
|
+
input = encoded.dup
|
36
|
+
processed = subject.decode!(input, subject::SKIP_SEPARATORS)
|
37
|
+
processed.must_equal decoded
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "skip_unicode" do
|
42
|
+
it "encodes correctly" do
|
43
|
+
input = "this is some \n text = with ה"
|
44
|
+
processed = subject.encode!(input, subject::SKIP_UNICODE)
|
45
|
+
expected = 'this\ is\ some\ \n\ text\ \=\ with\ ה'
|
46
|
+
processed.must_equal expected
|
47
|
+
end
|
48
|
+
|
49
|
+
it "decodes correctly" do
|
50
|
+
input = 'this\ is\ some\ \n\ text\ \=\ with\ \u05d4'
|
51
|
+
processed = subject.decode!(input, subject::SKIP_UNICODE)
|
52
|
+
expected = "this is some \n text = with " + '\u05d4'
|
53
|
+
processed.must_equal expected
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "skip_special_chars" do
|
58
|
+
it "encodes correctly" do
|
59
|
+
input = "this is some \n text = with ה"
|
60
|
+
processed = subject.encode!(input, subject::SKIP_SPECIAL_CHARS)
|
61
|
+
expected = 'this\ is\ some\ ' + "\n" + '\ text\ \=\ with\ \u05d4'
|
62
|
+
processed.must_equal expected
|
63
|
+
end
|
64
|
+
|
65
|
+
it "decodes correctly" do
|
66
|
+
input = 'this\ is\ some\ \n\ text\ \=\ with\ \u05d4'
|
67
|
+
processed = subject.decode!(input, subject::SKIP_SPECIAL_CHARS)
|
68
|
+
expected = 'this is some \n text = with ה'
|
69
|
+
processed.must_equal expected
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe ProperProperties::Generating::Generator do
|
5
|
+
subject { ProperProperties::Generating::Generator }
|
6
|
+
|
7
|
+
let(:as_hash) do
|
8
|
+
{
|
9
|
+
:item0 => "",
|
10
|
+
:item1 => "item1".freeze,
|
11
|
+
:item2 => "item2",
|
12
|
+
:item3 => "item3",
|
13
|
+
:"it em4".freeze => "item4",
|
14
|
+
:"it=em5" => "item5",
|
15
|
+
:"it:em6" => "item6",
|
16
|
+
:item7 => "line 1 line 2 line 3",
|
17
|
+
:item8 => "line 1 line 2 line 3",
|
18
|
+
:item9 => "line 1 line 2 line 3",
|
19
|
+
:item10 => "test\n\ttestה test\n\ttest test\n\ttest = test"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
it "generates properties file content" do
|
24
|
+
expected = fixture("test_out.properties")
|
25
|
+
content = subject.generate(as_hash)
|
26
|
+
content.must_equal expected
|
27
|
+
end
|
28
|
+
|
29
|
+
it "generates properties file content but skips unicode encoding" do
|
30
|
+
expected = fixture("test_out_skip_unicode.properties")
|
31
|
+
content = subject.generate(as_hash, :skip_encode_unicode => true)
|
32
|
+
content.must_equal expected
|
33
|
+
end
|
34
|
+
|
35
|
+
it "generates properties file content but skips separators encoding" do
|
36
|
+
expected = fixture("test_out_skip_separators.properties")
|
37
|
+
content = subject.generate(as_hash, :skip_encode_separators => true)
|
38
|
+
content.must_equal expected
|
39
|
+
end
|
40
|
+
|
41
|
+
it "generates properties file content but skips special chars encoding" do
|
42
|
+
expected = fixture("test_out_skip_special_chars.properties")
|
43
|
+
content = subject.generate(as_hash, :skip_encode_special_chars => true)
|
44
|
+
content.must_equal expected
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe ProperProperties::Parsing::Normalizer do
|
4
|
+
subject { ProperProperties::Parsing::Normalizer }
|
5
|
+
|
6
|
+
it "normalizes by applying all rules" do
|
7
|
+
content = fixture("test.properties")
|
8
|
+
normalized = fixture("test_normalized.properties")
|
9
|
+
subject.normalize! content
|
10
|
+
content.must_equal normalized
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe ProperProperties::Parsing::Parser do
|
4
|
+
subject { ProperProperties::Parsing::Parser }
|
5
|
+
|
6
|
+
let(:as_hash) do
|
7
|
+
{
|
8
|
+
:item0 => "",
|
9
|
+
:item1 => "item1 ",
|
10
|
+
:item2 => "item2 ",
|
11
|
+
:item3 => "item3",
|
12
|
+
:"it em4" => "item4",
|
13
|
+
:"it=em5" => "item5",
|
14
|
+
:item6 => "item6",
|
15
|
+
:item7 => "line 1 line 2 line 3",
|
16
|
+
:item8 => "line 1 #Not a Comment line 2 line 3",
|
17
|
+
:item9 => "line 1 line 2 line 3",
|
18
|
+
:item10 => "test\n\ttestP test\n\ttest test\n\ttest = test",
|
19
|
+
:item11 => "line 1 \\line 2 \\\\line 3 line 4",
|
20
|
+
:item12 => "line 1\\",
|
21
|
+
:item13 => "line 1"
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "parses correctly a properties file content" do
|
26
|
+
content = fixture("test.properties")
|
27
|
+
properties = subject.parse(content)
|
28
|
+
|
29
|
+
# don't compare the hashes directly, as this hard to debug
|
30
|
+
properties.keys.must_equal as_hash.keys
|
31
|
+
properties.each do |key, value|
|
32
|
+
value.must_equal as_hash[key]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe ProperProperties do
|
5
|
+
subject{ ProperProperties }
|
6
|
+
|
7
|
+
it "parses from string" do
|
8
|
+
subject.parse("item1=item1").must_equal({:item1 => "item1"})
|
9
|
+
end
|
10
|
+
|
11
|
+
it "generates from hash" do
|
12
|
+
subject.generate({:item1 => "item1"}).must_equal("item1=item1")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "loads from file" do
|
16
|
+
with_temp_file do |file|
|
17
|
+
file << "item1=item1"
|
18
|
+
file.flush
|
19
|
+
|
20
|
+
subject.load(file.path).must_equal({:item1 => "item1"})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "writes to file" do
|
25
|
+
with_temp_file do |file|
|
26
|
+
subject.write({:item1 => "item1"}, file.path)
|
27
|
+
|
28
|
+
file.rewind
|
29
|
+
file.read.must_equal "item1=item1"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def with_temp_file(&block)
|
36
|
+
file = Tempfile.new("proper_properties")
|
37
|
+
block.call(file)
|
38
|
+
ensure
|
39
|
+
file.close
|
40
|
+
file.unlink
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: proper_properties
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tnarik Innael
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: coveralls
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: simplecov
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Library for loading and writing of Java properties files that matches
|
70
|
+
java.util.Properties behaviour
|
71
|
+
email:
|
72
|
+
- tnarik@lecafeautomatique.co.uk
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/proper_properties.rb
|
84
|
+
- lib/proper_properties/encoding.rb
|
85
|
+
- lib/proper_properties/encoding/separators.rb
|
86
|
+
- lib/proper_properties/encoding/special_chars.rb
|
87
|
+
- lib/proper_properties/encoding/unicode.rb
|
88
|
+
- lib/proper_properties/generating.rb
|
89
|
+
- lib/proper_properties/generating/generator.rb
|
90
|
+
- lib/proper_properties/parsing.rb
|
91
|
+
- lib/proper_properties/parsing/normalizer.rb
|
92
|
+
- lib/proper_properties/parsing/parser.rb
|
93
|
+
- lib/proper_properties/properties.rb
|
94
|
+
- lib/proper_properties/version.rb
|
95
|
+
- proper_properties.gemspec
|
96
|
+
- spec/fixtures/test.properties
|
97
|
+
- spec/fixtures/test_normalized.properties
|
98
|
+
- spec/fixtures/test_out.properties
|
99
|
+
- spec/fixtures/test_out_skip_separators.properties
|
100
|
+
- spec/fixtures/test_out_skip_special_chars.properties
|
101
|
+
- spec/fixtures/test_out_skip_unicode.properties
|
102
|
+
- spec/helper.rb
|
103
|
+
- spec/proper_properties/encoding/separators_spec.rb
|
104
|
+
- spec/proper_properties/encoding/special_chars_spec.rb
|
105
|
+
- spec/proper_properties/encoding/unicode_spec.rb
|
106
|
+
- spec/proper_properties/encoding_spec.rb
|
107
|
+
- spec/proper_properties/generating/generator_spec.rb
|
108
|
+
- spec/proper_properties/parsing/normalizer_spec.rb
|
109
|
+
- spec/proper_properties/parsing/parser_spec.rb
|
110
|
+
- spec/proper_properties/version_spec.rb
|
111
|
+
- spec/proper_properties_spec.rb
|
112
|
+
homepage: https://github.com/tnarik/proper_properties
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
metadata: {}
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 2.2.2
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Loader and writer for Java properties files
|
136
|
+
test_files:
|
137
|
+
- spec/fixtures/test.properties
|
138
|
+
- spec/fixtures/test_normalized.properties
|
139
|
+
- spec/fixtures/test_out.properties
|
140
|
+
- spec/fixtures/test_out_skip_separators.properties
|
141
|
+
- spec/fixtures/test_out_skip_special_chars.properties
|
142
|
+
- spec/fixtures/test_out_skip_unicode.properties
|
143
|
+
- spec/helper.rb
|
144
|
+
- spec/proper_properties/encoding/separators_spec.rb
|
145
|
+
- spec/proper_properties/encoding/special_chars_spec.rb
|
146
|
+
- spec/proper_properties/encoding/unicode_spec.rb
|
147
|
+
- spec/proper_properties/encoding_spec.rb
|
148
|
+
- spec/proper_properties/generating/generator_spec.rb
|
149
|
+
- spec/proper_properties/parsing/normalizer_spec.rb
|
150
|
+
- spec/proper_properties/parsing/parser_spec.rb
|
151
|
+
- spec/proper_properties/version_spec.rb
|
152
|
+
- spec/proper_properties_spec.rb
|