php-composer 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -10
  3. data/Gemfile +15 -15
  4. data/LICENSE.txt +21 -21
  5. data/README.md +35 -35
  6. data/Rakefile +1 -1
  7. data/lib/composer.rb +52 -52
  8. data/lib/composer/error.rb +8 -8
  9. data/lib/composer/json/json_file.rb +270 -270
  10. data/lib/composer/package/alias_package.rb +273 -273
  11. data/lib/composer/package/base_package.rb +130 -130
  12. data/lib/composer/package/complete_package.rb +55 -55
  13. data/lib/composer/package/dumper/hash_dumper.rb +169 -169
  14. data/lib/composer/package/link.rb +51 -51
  15. data/lib/composer/package/link_constraint/base_constraint.rb +35 -35
  16. data/lib/composer/package/link_constraint/empty_constraint.rb +34 -34
  17. data/lib/composer/package/link_constraint/multi_constraint.rb +66 -66
  18. data/lib/composer/package/link_constraint/specific_constraint.rb +40 -40
  19. data/lib/composer/package/link_constraint/version_constraint.rb +220 -220
  20. data/lib/composer/package/loader/hash_loader.rb +316 -316
  21. data/lib/composer/package/loader/json_loader.rb +47 -47
  22. data/lib/composer/package/loader/project_attributes_loader.rb +71 -71
  23. data/lib/composer/package/loader/project_root_package_loader.rb +28 -28
  24. data/lib/composer/package/package.rb +118 -118
  25. data/lib/composer/package/root_alias_package.rb +37 -37
  26. data/lib/composer/package/root_package.rb +37 -37
  27. data/lib/composer/package/version/version_parser.rb +583 -583
  28. data/lib/composer/package/version/version_selector.rb +106 -106
  29. data/lib/composer/repository/filesystem_repository.rb +84 -85
  30. data/lib/composer/repository/{array_repository.rb → hash_repository.rb} +195 -195
  31. data/lib/composer/repository/{writeable_array_repository.rb → writeable_hash_repository.rb} +57 -59
  32. data/lib/composer/version.rb +3 -3
  33. data/php-composer.gemspec +31 -31
  34. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 057c61e3d36c2fa8ec1507fc3b3010b14e9cf68f
4
- data.tar.gz: 07cb396311c838990d32b02433d10df1c9f4e4de
3
+ metadata.gz: 8241ec13c67744cf1fd4170eb39936928677f4da
4
+ data.tar.gz: e24e4001f8e93ec75d30683a86118dc861010a8e
5
5
  SHA512:
6
- metadata.gz: 59e04a91ee1308295d684631cc6dbc9c8ec7e3c8d0ef1384f4e10218dd62136ef00f81209b7fe341aa3147e5f2133fa999e736dc446b34c1993d6f4c15236654
7
- data.tar.gz: 366721224c65b2ae87534b9f2d95c59def2458f1653562018ce0dbcb4f7d0ce26320771c9c60cc2244af89e9a718f88aef1204b0992eaea838ec3e96c1041e48
6
+ metadata.gz: c7e2fde5ee0935285a1a968957a39319bf010910e35c5d51559b7306a2df67314534af2313cf725742b79ab4125093d70f94149d2d346384c226f05540564467
7
+ data.tar.gz: 2ffa1805e88423b8385f15e0562b8e183bfe6a0e4796e27359853998131a9731ae62332edd0a410260f2d6a8b4de3e33a00e3880b0c17a872e294e0643da32a8
data/.gitignore CHANGED
@@ -1,10 +1,10 @@
1
- /.bundle/
2
- /.idea/
3
- /.yardoc
4
- /Gemfile.lock
5
- /_yardoc/
6
- /coverage/
7
- /doc/
8
- /pkg/
9
- /spec/reports/
10
- /tmp/
1
+ /.bundle/
2
+ /.idea/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/Gemfile CHANGED
@@ -1,15 +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
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 CHANGED
@@ -1,21 +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.
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 CHANGED
@@ -1,35 +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
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 CHANGED
@@ -1 +1 @@
1
- require 'bundler/gem_tasks'
1
+ require 'bundler/gem_tasks'
data/lib/composer.rb CHANGED
@@ -1,52 +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
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/hash_repository'
48
+ require 'composer/repository/writeable_hash_repository'
49
+ require 'composer/repository/filesystem_repository'
50
+
51
+ module Composer
52
+ end
@@ -1,8 +1,8 @@
1
- module Composer
2
- class Error < ::StandardError; end
3
- class ArgumentError < Error; end
4
- class TypeError < Error; end
5
- class UnexpectedValueError < Error; end
6
- class LogicError < Error; end
7
- class InvalidRepositoryError < Error; end
8
- end
1
+ module Composer
2
+ class Error < ::StandardError; end
3
+ class ArgumentError < Error; end
4
+ class TypeError < Error; end
5
+ class UnexpectedValueError < Error; end
6
+ class LogicError < Error; end
7
+ class InvalidRepositoryError < Error; end
8
+ end
@@ -1,270 +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
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