php-composer 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1006 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +21 -0
- data/README.md +35 -0
- data/Rakefile +1 -0
- data/lib/composer.rb +52 -0
- data/lib/composer/error.rb +8 -0
- data/lib/composer/json/json_file.rb +270 -0
- data/lib/composer/json/json_formatter.rb +159 -0
- data/lib/composer/json/json_validaton_error.rb +29 -0
- data/lib/composer/manager.rb +79 -0
- data/lib/composer/package/alias_package.rb +273 -0
- data/lib/composer/package/base_package.rb +130 -0
- data/lib/composer/package/complete_package.rb +55 -0
- data/lib/composer/package/dumper/hash_dumper.rb +169 -0
- data/lib/composer/package/link.rb +51 -0
- data/lib/composer/package/link_constraint/base_constraint.rb +36 -0
- data/lib/composer/package/link_constraint/empty_constraint.rb +35 -0
- data/lib/composer/package/link_constraint/multi_constraint.rb +67 -0
- data/lib/composer/package/link_constraint/specific_constraint.rb +41 -0
- data/lib/composer/package/link_constraint/version_constraint.rb +221 -0
- data/lib/composer/package/loader/hash_loader.rb +316 -0
- data/lib/composer/package/loader/json_loader.rb +47 -0
- data/lib/composer/package/loader/project_attributes_loader.rb +71 -0
- data/lib/composer/package/loader/project_root_package_loader.rb +28 -0
- data/lib/composer/package/package.rb +118 -0
- data/lib/composer/package/root_alias_package.rb +37 -0
- data/lib/composer/package/root_package.rb +37 -0
- data/lib/composer/package/version/version_parser.rb +583 -0
- data/lib/composer/package/version/version_selector.rb +106 -0
- data/lib/composer/provider.rb +94 -0
- data/lib/composer/repository/array_repository.rb +195 -0
- data/lib/composer/repository/filesystem_repository.rb +86 -0
- data/lib/composer/repository/writeable_array_repository.rb +60 -0
- data/lib/composer/version.rb +3 -0
- data/php-composer.gemspec +31 -0
- data/resources/composer-schema.json +421 -0
- metadata +188 -0
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in composer.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'json', '>= 1.7', :platforms => [:mri_18, :mri_19]
|
7
|
+
gem 'json-schema', '>= 2.5.0'
|
8
|
+
# gem 'version_compare', '~> 0.0.2'
|
9
|
+
gem 'digest-crc'
|
10
|
+
|
11
|
+
group :development, :test do
|
12
|
+
gem 'rubocop', '>= 0.28.0', require: false
|
13
|
+
gem 'rspec'
|
14
|
+
gem 'simplecov', '>= 0.9.2'
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015, Ioannis Kappas <ikappas@devworks.gr>
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# PHP Composer Ruby Gem
|
2
|
+
|
3
|
+
A ruby gem library for consistent interactions with php composer dependency manager.
|
4
|
+
|
5
|
+
This is a partial port of the [Composer - Dependency Management for PHP](https://github.com/composer/composer) project as a library that enables consistent interactions with php composer.
|
6
|
+
|
7
|
+
See [https://getcomposer.org/](https://getcomposer.org/) for more information.
|
8
|
+
|
9
|
+
## Installation / Usage
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'php-composer'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install php-composer
|
23
|
+
|
24
|
+
## Authors
|
25
|
+
Ioannis Kappas - <ikappas@devworks.gr>
|
26
|
+
|
27
|
+
## License
|
28
|
+
PHP Composer Ruby Gem is licensed under the MIT License - see the LICENSE file for details
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
1. Fork it ( https://github.com/ikappas/php-composer/fork )
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/composer.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# external
|
2
|
+
require 'json'
|
3
|
+
require 'json-schema'
|
4
|
+
|
5
|
+
# /
|
6
|
+
require 'composer/version'
|
7
|
+
require 'composer/error'
|
8
|
+
|
9
|
+
# /json
|
10
|
+
require 'composer/json/json_validaton_error'
|
11
|
+
require 'composer/json/json_file'
|
12
|
+
require 'composer/json/json_formatter'
|
13
|
+
|
14
|
+
# /package
|
15
|
+
require 'composer/package/base_package'
|
16
|
+
require 'composer/package/package'
|
17
|
+
require 'composer/package/complete_package'
|
18
|
+
require 'composer/package/alias_package'
|
19
|
+
require 'composer/package/root_alias_package'
|
20
|
+
require 'composer/package/root_package'
|
21
|
+
require 'composer/package/link'
|
22
|
+
|
23
|
+
# /package/dumper
|
24
|
+
require 'composer/package/dumper/hash_dumper'
|
25
|
+
|
26
|
+
# /package/link_constraint
|
27
|
+
require 'composer/package/link_constraint/base_constraint'
|
28
|
+
require 'composer/package/link_constraint/empty_constraint'
|
29
|
+
require 'composer/package/link_constraint/specific_constraint'
|
30
|
+
require 'composer/package/link_constraint/version_constraint'
|
31
|
+
require 'composer/package/link_constraint/multi_constraint'
|
32
|
+
|
33
|
+
# /package/loader
|
34
|
+
require 'composer/package/loader/hash_loader'
|
35
|
+
require 'composer/package/loader/json_loader'
|
36
|
+
|
37
|
+
# /package/version
|
38
|
+
require 'composer/package/version/version_parser'
|
39
|
+
require 'composer/package/version/version_selector'
|
40
|
+
|
41
|
+
# Dir[File.join(File.dirname(__FILE__), "composer/package/dumper/*.rb")].each {|file| require file }
|
42
|
+
# Dir[File.join(File.dirname(__FILE__), "composer/package/link_constraint/*.rb")].each {|file| require file }
|
43
|
+
# Dir[File.join(File.dirname(__FILE__), "composer/package/loader/*.rb")].each {|file| require file }
|
44
|
+
# Dir[File.join(File.dirname(__FILE__), "composer/package/version/*.rb")].each {|file| require file }
|
45
|
+
|
46
|
+
# /repository
|
47
|
+
require 'composer/repository/array_repository'
|
48
|
+
require 'composer/repository/writeable_array_repository'
|
49
|
+
require 'composer/repository/filesystem_repository'
|
50
|
+
|
51
|
+
module Composer
|
52
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
#
|
2
|
+
# This file was ported to ruby from Composer php source code file.
|
3
|
+
# Original Source: Composer\Json\JsonFile.php
|
4
|
+
#
|
5
|
+
# (c) Nils Adermann <naderman@naderman.de>
|
6
|
+
# Jordi Boggiano <j.boggiano@seld.be>
|
7
|
+
#
|
8
|
+
# For the full copyright and license information, please view the LICENSE
|
9
|
+
# file that was distributed with this source code.
|
10
|
+
#
|
11
|
+
|
12
|
+
module Composer
|
13
|
+
module Json
|
14
|
+
# Reads/writes json files.
|
15
|
+
#
|
16
|
+
# PHP Authors:
|
17
|
+
# Konstantin Kudryashiv <ever.zet@gmail.com>
|
18
|
+
# Jordi Boggiano <j.boggiano@seld.be>
|
19
|
+
#
|
20
|
+
# Ruby Authors:
|
21
|
+
# Ioannis Kappas <ikappas@devworks.gr>
|
22
|
+
class JsonFile
|
23
|
+
attr_reader :path
|
24
|
+
|
25
|
+
LAX_SCHEMA = 1
|
26
|
+
STRICT_SCHEMA = 2
|
27
|
+
|
28
|
+
JSON_ERROR_NONE = 0
|
29
|
+
JSON_ERROR_DEPTH = 1
|
30
|
+
JSON_ERROR_STATE_MISMATCH = 2
|
31
|
+
JSON_ERROR_CTRL_CHAR = 3
|
32
|
+
JSON_ERROR_SYNTAX = 4
|
33
|
+
JSON_ERROR_UTF8 = 5
|
34
|
+
JSON_ERROR_RECURSION = 6
|
35
|
+
JSON_ERROR_INF_OR_NAN = 7
|
36
|
+
JSON_ERROR_UNSUPPORTED_TYPE = 8
|
37
|
+
|
38
|
+
# Initializes json file reader/parser.
|
39
|
+
# @param [String] path path to a json file
|
40
|
+
# @param [RemoteFileSystem] rfs The remote filesystem to use for http/https json files
|
41
|
+
# @raise [ArgumentError]
|
42
|
+
def initialize(path, rfs = nil)
|
43
|
+
@path = path
|
44
|
+
if rfs === nil && /^https?:\/\//i.match(path)
|
45
|
+
raise ArgumentError,
|
46
|
+
'http urls require a RemoteFilesystem instance to be passed'
|
47
|
+
end
|
48
|
+
@rfs = rfs
|
49
|
+
end
|
50
|
+
|
51
|
+
# Checks whether this json file exists.
|
52
|
+
#
|
53
|
+
# Returns:
|
54
|
+
# true if this json file exists; otherwise false.
|
55
|
+
def exist?
|
56
|
+
File.exist?(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Reads the json file.
|
60
|
+
#
|
61
|
+
# Raises:
|
62
|
+
# RuntimeError
|
63
|
+
#
|
64
|
+
# Returns:
|
65
|
+
# mixed
|
66
|
+
def read
|
67
|
+
if @rfs
|
68
|
+
json = @rfs.get_contents(@path, @path, false)
|
69
|
+
else
|
70
|
+
json = File.open(@path, 'r') { |f| f.read }
|
71
|
+
end
|
72
|
+
|
73
|
+
parse_json(json, @path)
|
74
|
+
|
75
|
+
rescue Exception => e
|
76
|
+
raise e
|
77
|
+
end
|
78
|
+
|
79
|
+
def write(hash, options = 448)
|
80
|
+
dir = File.dirname(@path)
|
81
|
+
|
82
|
+
unless File.directory?(storage_path)
|
83
|
+
if File.exist?(dir)
|
84
|
+
raise UnexpectedValueError,
|
85
|
+
"#{dir} exists and is not a directory."
|
86
|
+
end
|
87
|
+
FileUtils.mkdir_p(dir, 0777)
|
88
|
+
end
|
89
|
+
|
90
|
+
retries = 3
|
91
|
+
while retries >= 0
|
92
|
+
begin
|
93
|
+
file_ending = options & JSON_PRETTY_PRINT ? "\n" : ''
|
94
|
+
File.open(path, 'w') do |f|
|
95
|
+
content = encode(hash, options) + file_ending
|
96
|
+
f.write(content)
|
97
|
+
end
|
98
|
+
break
|
99
|
+
|
100
|
+
rescue Exception => e
|
101
|
+
if retries
|
102
|
+
retries -= 1
|
103
|
+
sleep 0.5
|
104
|
+
else
|
105
|
+
raise e
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
# Validates the schema of the current json file according
|
113
|
+
# to composer-schema.json rules
|
114
|
+
#
|
115
|
+
# @param schema int a JsonFile::*_SCHEMA constant
|
116
|
+
# @return bool true if schema is valid; Otherwise false.
|
117
|
+
# @throw Composer::Json::JsonValidationError
|
118
|
+
def validate_schema(schema = STRICT_SCHEMA)
|
119
|
+
content = File.open(@path, 'r') { |f| f.read }
|
120
|
+
data = JSON.parse(content)
|
121
|
+
|
122
|
+
if data == nil && content != 'null'
|
123
|
+
self::validate_syntax(content, @path)
|
124
|
+
end
|
125
|
+
|
126
|
+
schema_file = File.join(
|
127
|
+
File.dirname(__FILE__),
|
128
|
+
'../../../resources/composer-schema.json'
|
129
|
+
)
|
130
|
+
|
131
|
+
schema_data = JSON.parse(
|
132
|
+
File.open(schema_file, 'r') { |f| f.read }
|
133
|
+
)
|
134
|
+
|
135
|
+
if schema === LAX_SCHEMA
|
136
|
+
schema_data['additionalProperties'] = true
|
137
|
+
schema_data['properties']['name']['required'] = false
|
138
|
+
schema_data['properties']['description']['required'] = false
|
139
|
+
end
|
140
|
+
|
141
|
+
errors = JSON::Validator.fully_validate(
|
142
|
+
schema_data,
|
143
|
+
data,
|
144
|
+
{:errors_as_objects => true}
|
145
|
+
)
|
146
|
+
|
147
|
+
unless errors.empty?
|
148
|
+
processed_errors = []
|
149
|
+
errors.each do |error|
|
150
|
+
prefix = error[:fragment] ? "#{error[:fragment]} : " : ''
|
151
|
+
processed_errors.push( prefix + error[:message])
|
152
|
+
end
|
153
|
+
raise Composer::Json::JsonValidationError.new(processed_errors),
|
154
|
+
"\"#{@path}\" does not match the expected JSON schema"
|
155
|
+
end
|
156
|
+
|
157
|
+
true
|
158
|
+
end
|
159
|
+
|
160
|
+
class << self
|
161
|
+
|
162
|
+
# Encodes an hash into (optionally pretty-printed) JSON
|
163
|
+
#
|
164
|
+
# @param data mixed Data to encode into a formatted JSON string
|
165
|
+
# @param options int json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
166
|
+
# @return string Encoded json
|
167
|
+
def encode(data, options = 448)
|
168
|
+
|
169
|
+
# if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
170
|
+
# $json = json_encode(data, options);
|
171
|
+
|
172
|
+
# # compact brackets to follow recent php versions
|
173
|
+
# if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
|
174
|
+
# $json = preg_replace('/\[\s+\]/', '[]', $json);
|
175
|
+
# $json = preg_replace('/\{\s+\}/', '{}', $json);
|
176
|
+
# }
|
177
|
+
|
178
|
+
# return $json;
|
179
|
+
# }
|
180
|
+
|
181
|
+
# * *indent*: a string used to indent levels (default: ''),
|
182
|
+
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
183
|
+
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
184
|
+
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
185
|
+
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
186
|
+
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
187
|
+
# generated, otherwise an exception is thrown if these values are
|
188
|
+
# encountered. This options defaults to false.
|
189
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the data
|
190
|
+
# structures from which JSON is to be generated. Disable depth checking
|
191
|
+
# with :max_nesting => false, it defaults to 100.
|
192
|
+
|
193
|
+
if data.nil?
|
194
|
+
return 'null'
|
195
|
+
elsif data.is_a?(TrueClass)
|
196
|
+
return 'true'
|
197
|
+
elsif data.is_a?(FalseClass)
|
198
|
+
return 'false'
|
199
|
+
elsif data.is_a?(Integer)
|
200
|
+
return Integer(data)
|
201
|
+
elsif data.is_a?(Float)
|
202
|
+
return Float(data)
|
203
|
+
else
|
204
|
+
begin
|
205
|
+
json = JSON.generate(data, { quirks_mode: false })
|
206
|
+
rescue JSON::GeneratorError => e
|
207
|
+
if e.message === 'only generation of JSON objects or arrays allowed'
|
208
|
+
#trick into parsing scalar values by wrapping them in an array
|
209
|
+
scalar = data.gsub("\\\\", "\\\\\\")
|
210
|
+
if json = JSON::generate([scalar])
|
211
|
+
json = json[1..(json.length - 2)]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
return json unless options
|
218
|
+
|
219
|
+
result = Composer::Json::JsonFormatter::format(
|
220
|
+
json,
|
221
|
+
options
|
222
|
+
)
|
223
|
+
|
224
|
+
result
|
225
|
+
end
|
226
|
+
|
227
|
+
# Parses json string and returns hash.
|
228
|
+
#
|
229
|
+
# Params:
|
230
|
+
# +json+ string The json string to parse
|
231
|
+
# +file+ string The json file
|
232
|
+
#
|
233
|
+
# Returns:
|
234
|
+
# mixed
|
235
|
+
def parse_json(json, file = nil)
|
236
|
+
last_error = JSON_ERROR_NONE
|
237
|
+
|
238
|
+
begin
|
239
|
+
data = JSON.parse(json)
|
240
|
+
rescue Exception => e
|
241
|
+
last_error = e
|
242
|
+
end
|
243
|
+
|
244
|
+
if data.nil? && last_error != JSON_ERROR_NONE
|
245
|
+
validate_syntax(json, file)
|
246
|
+
raise JSON::ParserError,
|
247
|
+
"\"#{file}\" does not contain valid JSON\n
|
248
|
+
#{last_error.message}"
|
249
|
+
end
|
250
|
+
|
251
|
+
data
|
252
|
+
end
|
253
|
+
|
254
|
+
def validate_syntax(json, file)
|
255
|
+
# JSON::
|
256
|
+
# parser = Composer::Json::JsonParser.new
|
257
|
+
# if (result = parser.lint(json))
|
258
|
+
# raise ParsingError,
|
259
|
+
# "\"#{file}\" does not contain valid JSON\n
|
260
|
+
# #{result.message}"
|
261
|
+
# end
|
262
|
+
# if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) {
|
263
|
+
# throw new \UnexpectedValueException('"'.$file.'" is not UTF-8, could not parse as JSON');
|
264
|
+
# }
|
265
|
+
true
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
#
|
2
|
+
# This file was ported to ruby from Composer php source code file.
|
3
|
+
# Original Source: Composer\Json\JsonFormatter.php
|
4
|
+
#
|
5
|
+
# (c) Nils Adermann <naderman@naderman.de>
|
6
|
+
# Jordi Boggiano <j.boggiano@seld.be>
|
7
|
+
#
|
8
|
+
# For the full copyright and license information, please view the LICENSE
|
9
|
+
# file that was distributed with this source code.
|
10
|
+
#
|
11
|
+
|
12
|
+
# JSON_HEX_TAG => 1
|
13
|
+
# JSON_HEX_AMP => 2
|
14
|
+
# JSON_HEX_APOS => 4
|
15
|
+
# JSON_HEX_QUOT => 8
|
16
|
+
# JSON_FORCE_OBJECT => 16
|
17
|
+
# JSON_NUMERIC_CHECK => 32
|
18
|
+
# JSON_UNESCAPED_SLASHES => 64
|
19
|
+
# JSON_PRETTY_PRINT => 128
|
20
|
+
# JSON_UNESCAPED_UNICODE => 256
|
21
|
+
|
22
|
+
module Composer
|
23
|
+
module Json
|
24
|
+
# * Formats json strings used for php < 5.4 because the json_encode doesn't
|
25
|
+
# * supports the flags JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
|
26
|
+
# * in these versions
|
27
|
+
#
|
28
|
+
# PHP Authors:
|
29
|
+
# Konstantin Kudryashiv <ever.zet@gmail.com>
|
30
|
+
# Jordi Boggiano <j.boggiano@seld.be>
|
31
|
+
#
|
32
|
+
# Ruby Authors:
|
33
|
+
# Ioannis Kappas <ikappas@devworks.gr>
|
34
|
+
class JsonFormatter
|
35
|
+
|
36
|
+
JSON_HEX_TAG = 1
|
37
|
+
JSON_HEX_AMP = 2
|
38
|
+
JSON_HEX_APOS = 4
|
39
|
+
JSON_HEX_QUOT = 8
|
40
|
+
JSON_FORCE_OBJECT = 16
|
41
|
+
JSON_NUMERIC_CHECK = 32
|
42
|
+
JSON_UNESCAPED_SLASHES = 64
|
43
|
+
JSON_PRETTY_PRINT = 128
|
44
|
+
JSON_UNESCAPED_UNICODE = 256
|
45
|
+
|
46
|
+
class << self
|
47
|
+
# This code is based on the function found at:
|
48
|
+
# http://recursive-design.com/blog/2008/03/11/format-json-with-php/
|
49
|
+
#
|
50
|
+
# Originally licensed under MIT by Dave Perrett <mail@recursive-design.com>
|
51
|
+
#
|
52
|
+
# @param json string
|
53
|
+
# @param unescape_unicode bool Un escape unicode
|
54
|
+
# @param unescape_slashes bool Un escape slashes
|
55
|
+
# @return string
|
56
|
+
def format(json, options)
|
57
|
+
|
58
|
+
result = ''
|
59
|
+
pos = 0
|
60
|
+
str_len = json.length
|
61
|
+
indent_str = ' '
|
62
|
+
new_line = "\n"
|
63
|
+
out_of_quotes = true
|
64
|
+
buffer = ''
|
65
|
+
no_escape = true
|
66
|
+
|
67
|
+
for i in 0..(str_len - 1)
|
68
|
+
|
69
|
+
# Grab the next character in the string
|
70
|
+
char = json[i]
|
71
|
+
|
72
|
+
# Are we inside a quoted string?
|
73
|
+
if '"' === char && no_escape
|
74
|
+
out_of_quotes = !out_of_quotes
|
75
|
+
end
|
76
|
+
|
77
|
+
if !out_of_quotes
|
78
|
+
buffer << char
|
79
|
+
no_escape = '\\' === char ? !no_escape : true
|
80
|
+
next
|
81
|
+
elsif buffer != ''
|
82
|
+
if options & JSON_HEX_TAG === JSON_HEX_TAG
|
83
|
+
buffer.gsub!('<', '\\u003C')
|
84
|
+
buffer.gsub!('>', '\\u003E')
|
85
|
+
end
|
86
|
+
if options & JSON_HEX_AMP === JSON_HEX_AMP
|
87
|
+
buffer.gsub!('&', '\\u0026')
|
88
|
+
end
|
89
|
+
if options & JSON_HEX_APOS === JSON_HEX_APOS
|
90
|
+
buffer.gsub!('\'', '\\u0027')
|
91
|
+
end
|
92
|
+
if options & JSON_HEX_QUOT === JSON_HEX_QUOT
|
93
|
+
buffer.gsub!('\"', '\\u0022')
|
94
|
+
end
|
95
|
+
if options & JSON_UNESCAPED_SLASHES === JSON_UNESCAPED_SLASHES
|
96
|
+
buffer.gsub!('\\/', '/')
|
97
|
+
end
|
98
|
+
if options & JSON_UNESCAPED_UNICODE === JSON_UNESCAPED_UNICODE
|
99
|
+
buffer.gsub!(/\\u([\da-fA-F]{4})/) {|m| [$1].pack('H*').unpack('n*').pack('U*')}
|
100
|
+
end
|
101
|
+
|
102
|
+
result << buffer + char
|
103
|
+
buffer = ''
|
104
|
+
next
|
105
|
+
end
|
106
|
+
|
107
|
+
if options & JSON_PRETTY_PRINT === JSON_PRETTY_PRINT
|
108
|
+
if char === ':'
|
109
|
+
# Add a space after the : character
|
110
|
+
char << ' '
|
111
|
+
elsif char === '}' || char === ']'
|
112
|
+
pos -= 1
|
113
|
+
prev_char = json[i - 1] #substr(json, i - 1, 1)
|
114
|
+
|
115
|
+
if prev_char != '{' && prev_char != '['
|
116
|
+
# If this character is the end of an element,
|
117
|
+
# output a new line and indent the next line
|
118
|
+
result << new_line
|
119
|
+
|
120
|
+
for j in 0..(pos - 1)
|
121
|
+
result << indent_str
|
122
|
+
end
|
123
|
+
else
|
124
|
+
# Collapse empty {} and []
|
125
|
+
result.rstrip!
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
result << char
|
131
|
+
|
132
|
+
if options & JSON_PRETTY_PRINT === JSON_PRETTY_PRINT
|
133
|
+
# If the last character was the beginning of an element,
|
134
|
+
# output a new line and indent the next line
|
135
|
+
if char === ',' || char === '{' || char === '['
|
136
|
+
result << new_line
|
137
|
+
pos += 1 if char === '{' || char === '['
|
138
|
+
for j in 0..(pos - 1)
|
139
|
+
result << indent_str
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
result
|
146
|
+
end
|
147
|
+
|
148
|
+
def unescape_slashes(s)
|
149
|
+
s.gsub('\\/', '/')
|
150
|
+
end
|
151
|
+
|
152
|
+
def unescape_unicode(s)
|
153
|
+
s.gsub(/\\u([\da-fA-F]{4})/) {|m| [$1].pack('H*').unpack('n*').pack('U*')}
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|