php-composer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|