php-composer 0.1.1 → 0.2.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.
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