class_from_son 0.1.5 → 0.2.1
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 +4 -4
- data/README.md +14 -2
- data/lib/class_from_SON.rb +134 -17
- data/test/test_class_from_son.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7faa342b7ee967052d435004f43ce42c65da00131023013fc42309ce6a9e8808
|
4
|
+
data.tar.gz: 356699a2d3b8f2df84da9010cc03fa33c779e3ca1bb6dbdfa11cfbb2568487aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bbd9f6ca9246dc4b273a037e322bf4da6ce69258c120fc56f5ba2240b4a5047020867ed16cd86833c2a7dd4806855174acea4cabcb272e25a4527d821042e5f
|
7
|
+
data.tar.gz: 1b7967cffab7c886230b0d726260516441dfaf320d7238d50b201d2b655340d1446396ec9eb57b477b7a5122fd6c842954baf20a89b65b6934182e78f2bfdd62
|
data/README.md
CHANGED
@@ -31,6 +31,12 @@ or
|
|
31
31
|
ruby -e "require 'class_from_son'; ClassFromSON.generate :ruby, my_json_string, :json"
|
32
32
|
```
|
33
33
|
|
34
|
+
Advanced use :
|
35
|
+
|
36
|
+
```
|
37
|
+
ruby -e "require 'class_from_son'; ClassFromSON.generate :ruby, my_json_string, :json, true, false, true, '../write/files/somewhere/else'"
|
38
|
+
```
|
39
|
+
|
34
40
|
Method parameter explanations :
|
35
41
|
|
36
42
|
```
|
@@ -42,7 +48,10 @@ Method parameter explanations :
|
|
42
48
|
# source_lang is symbol or nil (if nil, source language will be determined from the file extension)
|
43
49
|
# make_file flag defaults to true; set to false if you do not want files to be created by this method
|
44
50
|
# force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
|
45
|
-
|
51
|
+
# lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
|
52
|
+
# as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
|
53
|
+
# custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
|
54
|
+
def ClassFromSON.generate_from_file(dest_lang, file, source_lang = nil, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
|
46
55
|
```
|
47
56
|
|
48
57
|
```
|
@@ -54,5 +63,8 @@ def ClassFromSON.generate_from_file(dest_lang, file, source_lang, make_file = tr
|
|
54
63
|
# source_lang is symbol
|
55
64
|
# make_file flag defaults to true; set to false if you do not want files to be created by this method
|
56
65
|
# force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
|
57
|
-
|
66
|
+
# lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
|
67
|
+
# as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
|
68
|
+
# custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
|
69
|
+
def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
|
58
70
|
```
|
data/lib/class_from_SON.rb
CHANGED
@@ -172,15 +172,16 @@ class ClassFromSON
|
|
172
172
|
|
173
173
|
# Returns code representing the start of the class
|
174
174
|
def generate_class_start(name)
|
175
|
+
# TODO make this more readable
|
175
176
|
case @language
|
176
|
-
when :java
|
177
|
+
when :java
|
177
178
|
start = <<-START
|
178
179
|
|
179
180
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
180
181
|
|
181
182
|
public class #{convert_custom_class_type(name)} {
|
182
183
|
START
|
183
|
-
when :java_lombok
|
184
|
+
when :java_lombok
|
184
185
|
start = <<-START
|
185
186
|
|
186
187
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
@@ -199,7 +200,16 @@ import lombok.Setter;
|
|
199
200
|
public class #{convert_custom_class_type(name)} {
|
200
201
|
START
|
201
202
|
when :ruby
|
202
|
-
|
203
|
+
case @mode
|
204
|
+
when :json
|
205
|
+
start = <<-START
|
206
|
+
require 'json'
|
207
|
+
|
208
|
+
class #{convert_custom_class_type(name)}
|
209
|
+
START
|
210
|
+
else
|
211
|
+
error_and_exit "Cannot parse mode #{@mode}"
|
212
|
+
end
|
203
213
|
else
|
204
214
|
error_and_exit "Could not convert to output language #{@language}"
|
205
215
|
end
|
@@ -225,13 +235,17 @@ START
|
|
225
235
|
when :java_lombok
|
226
236
|
# do nothing - Lombok's raison d'etre is to avoid getters & setters
|
227
237
|
when :java
|
228
|
-
|
238
|
+
# This is safe even if the name is already in snakecase
|
239
|
+
field_name_for_getter = name.snakecase.pascalcase
|
240
|
+
|
241
|
+
name = name.camelcase if name.include? "_"
|
242
|
+
|
229
243
|
lines << "\t"
|
230
|
-
lines << "\tpublic #{type} get#{
|
244
|
+
lines << "\tpublic #{type} get#{field_name_for_getter}() {"
|
231
245
|
lines << "\t\treturn #{name};"
|
232
246
|
lines << "\t}"
|
233
247
|
lines << "\t"
|
234
|
-
lines << "\tpublic void set#{
|
248
|
+
lines << "\tpublic void set#{field_name_for_getter}(#{type} #{name}) {"
|
235
249
|
lines << "\t\tthis.#{name} = #{name};"
|
236
250
|
lines << "\t}"
|
237
251
|
else
|
@@ -262,6 +276,7 @@ START
|
|
262
276
|
camelcase_name = att[:name].camelcase
|
263
277
|
code << "\t@JsonProperty(\"#{snakecase_name}\")"
|
264
278
|
code << "\tprivate #{convert_ruby_type_to_type(att[:type], att[:value_types])} #{camelcase_name};"
|
279
|
+
code << "" # add a new line so that fields are separated & easier to read
|
265
280
|
else
|
266
281
|
code << "\tprivate #{convert_ruby_type_to_type(att[:type], att[:value_types])} #{att[:name]};"
|
267
282
|
end
|
@@ -280,21 +295,83 @@ START
|
|
280
295
|
def generate_ruby_code_from_attributes(attributes)
|
281
296
|
code = []
|
282
297
|
names = []
|
283
|
-
attributes.each {|att| names << att[:name]}
|
298
|
+
attributes.each {|att| names << att[:name].snakecase}
|
284
299
|
|
285
300
|
# Instance variables
|
286
301
|
names.each do |name|
|
287
|
-
code << "
|
302
|
+
code << " attr_accessor #{name.to_sym.inspect}"
|
288
303
|
end
|
289
304
|
code << "" # An empty string is enough to trigger a newline
|
290
305
|
|
291
306
|
# Constructor
|
292
|
-
|
307
|
+
# This is deliberately commented out, in favour of self.from_hash
|
308
|
+
code << " # Using self.from_hash(hash) is usually better, but this code is here in case you prefer this style of constructor"
|
309
|
+
code << " # def initialize(#{names.join(", ")})"
|
293
310
|
names.each do |name|
|
294
|
-
code << "
|
311
|
+
code << " # @#{name} = #{name}"
|
312
|
+
end
|
313
|
+
code << " # end"
|
314
|
+
code
|
315
|
+
end
|
316
|
+
|
317
|
+
# Returns code for a from_SON and to_SON method
|
318
|
+
def generate_from_and_to_methods(classname, attributes)
|
319
|
+
case @language
|
320
|
+
when :java, :java_lombok
|
321
|
+
return generate_java_from_and_to_methods(classname, attributes)
|
322
|
+
when :ruby
|
323
|
+
return generate_ruby_from_and_to_methods(classname, attributes)
|
324
|
+
else
|
325
|
+
error_and_exit "Could not convert to output language #{@language}"
|
295
326
|
end
|
296
|
-
|
327
|
+
end
|
297
328
|
|
329
|
+
# Returns Java code for a from_SON and to_SON method
|
330
|
+
def generate_java_from_and_to_methods(classname, attributes)
|
331
|
+
code = []
|
332
|
+
# TODO
|
333
|
+
code
|
334
|
+
end
|
335
|
+
|
336
|
+
# Returns Ruby code for a from_SON and to_SON method
|
337
|
+
def generate_ruby_from_and_to_methods(classname, attributes)
|
338
|
+
code = []
|
339
|
+
names = []
|
340
|
+
attributes.each {|att| names << att[:name].snakecase}
|
341
|
+
|
342
|
+
# from_hash method
|
343
|
+
code << ""
|
344
|
+
code << " def self.from_hash(h)"
|
345
|
+
code << " o = self.new"
|
346
|
+
names.each do |name|
|
347
|
+
code << " o.#{name} = h[:#{name}]"
|
348
|
+
end
|
349
|
+
code << " o"
|
350
|
+
code << " end"
|
351
|
+
|
352
|
+
# from_SON method
|
353
|
+
code << ""
|
354
|
+
code << " def self.from_#{@mode}(#{@mode})"
|
355
|
+
case @mode
|
356
|
+
when :json
|
357
|
+
code << " self.from_hash(JSON.parse(#{@mode}))"
|
358
|
+
# TODO other input languages, e.g. XML, YAML
|
359
|
+
end
|
360
|
+
code << " end"
|
361
|
+
|
362
|
+
# to_SON method
|
363
|
+
code << ""
|
364
|
+
code << " def to_#{@mode}"
|
365
|
+
code << " h = {}"
|
366
|
+
names.each do |name|
|
367
|
+
code << " h[:#{name}] = @#{name}"
|
368
|
+
end
|
369
|
+
case @mode
|
370
|
+
when :json
|
371
|
+
code << " JSON.generate(h)"
|
372
|
+
# TODO other input languages, e.g. XML, YAML
|
373
|
+
end
|
374
|
+
code << " end"
|
298
375
|
code
|
299
376
|
end
|
300
377
|
|
@@ -332,6 +409,7 @@ START
|
|
332
409
|
end
|
333
410
|
|
334
411
|
lines << generate_code_from_attributes(attributes)
|
412
|
+
lines << generate_from_and_to_methods(classname, attributes)
|
335
413
|
lines << generate_class_end
|
336
414
|
lines.flatten!
|
337
415
|
this_file[:contents] = lines.join("\n")
|
@@ -351,13 +429,16 @@ START
|
|
351
429
|
# source_lang is symbol or nil (if nil, source language will be determined from the file extension)
|
352
430
|
# make_file flag defaults to true; set to false if you do not want files to be created by this method
|
353
431
|
# force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
|
354
|
-
|
432
|
+
# lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
|
433
|
+
# as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
|
434
|
+
# custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
|
435
|
+
def ClassFromSON.generate_from_file(dest_lang, file, source_lang = nil, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
|
355
436
|
|
356
437
|
error_and_exit "Could not locate file #{file}" unless File.exists?(file)
|
357
438
|
|
358
439
|
source_lang ||= File.extname(file).gsub(".", "")
|
359
440
|
source = File.readlines(file).join
|
360
|
-
ClassFromSON.generate(dest_lang, source, source_lang, make_file, force_file)
|
441
|
+
ClassFromSON.generate(dest_lang, source, source_lang, make_file, force_file, lenient_mode, custom_file_path)
|
361
442
|
|
362
443
|
# o = ClassFromSON.new
|
363
444
|
# o.generate(dest_lang, source, source_lang, make_file)
|
@@ -371,9 +452,12 @@ START
|
|
371
452
|
# source_lang is symbol
|
372
453
|
# make_file flag defaults to true; set to false if you do not want files to be created by this method
|
373
454
|
# force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
|
374
|
-
|
455
|
+
# lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
|
456
|
+
# as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
|
457
|
+
# custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
|
458
|
+
def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
|
375
459
|
o = ClassFromSON.new
|
376
|
-
o.generate(dest_lang, source, source_lang, make_file, force_file)
|
460
|
+
o.generate(dest_lang, source, source_lang, make_file, force_file, lenient_mode, custom_file_path)
|
377
461
|
end
|
378
462
|
|
379
463
|
# Will generate classes from a SON string.
|
@@ -384,7 +468,10 @@ START
|
|
384
468
|
# source_lang is symbol
|
385
469
|
# make_file flag defaults to true; set to false if you do not want files to be created by this method
|
386
470
|
# force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
|
387
|
-
|
471
|
+
# lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
|
472
|
+
# as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
|
473
|
+
# custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
|
474
|
+
def generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
|
388
475
|
|
389
476
|
error_and_exit "Please supply first argument as a Symbol" unless dest_lang.class == Symbol
|
390
477
|
|
@@ -429,16 +516,46 @@ START
|
|
429
516
|
top_level_classname = generate_top_level_name
|
430
517
|
output_classes = generate_output_classes(hash, top_level_classname).flatten # returns an array
|
431
518
|
|
519
|
+
# Set the directory that the files will be written into
|
520
|
+
if custom_file_path
|
521
|
+
# This caters for both absolute & relative file paths
|
522
|
+
file_path = File.absolute_path(custom_file_path)
|
523
|
+
else
|
524
|
+
file_path = Dir.getwd
|
525
|
+
end
|
526
|
+
|
527
|
+
# Track the names of the classes/files we have written so far
|
528
|
+
written_file_names = []
|
529
|
+
|
432
530
|
if make_file
|
433
531
|
output_classes.each do |out|
|
434
532
|
name = out[:name_with_ext]
|
533
|
+
# Check the name against the files we have already written
|
534
|
+
if written_file_names.include?(name)
|
535
|
+
if lenient_mode
|
536
|
+
# Let us increment the name, e.g. "data.rb" -> "data_1.rb", "data_2.rb", etc.
|
537
|
+
increment = 1
|
538
|
+
new_name = name.gsub(@extension, "_#{increment}#{@extension}")
|
539
|
+
while written_file_names.include?(new_name)
|
540
|
+
increment += 1
|
541
|
+
new_name = name.gsub(@extension, "_#{increment}#{@extension}")
|
542
|
+
end
|
543
|
+
name = new_name
|
544
|
+
else
|
545
|
+
message = "Want to generate output file #{name}, but a file with that name has already been written by this process. Your SON structure contains 2+ different classes with the same name"
|
546
|
+
error_and_exit(message)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
filename = file_path + File::SEPARATOR + name
|
435
551
|
contents = out[:contents]
|
436
552
|
unless force_file
|
437
553
|
error_and_exit "Want to generate output file #{name}, but that file already exists" if File.exists?(name)
|
438
554
|
end
|
439
|
-
File.open(
|
555
|
+
File.open(filename, "w+") do |f|
|
440
556
|
f.puts contents
|
441
557
|
end
|
558
|
+
written_file_names << name
|
442
559
|
puts "Wrote out file #{name}"
|
443
560
|
end
|
444
561
|
|
data/test/test_class_from_son.rb
CHANGED
@@ -19,7 +19,7 @@ class TestEx < Test::Unit::TestCase
|
|
19
19
|
|
20
20
|
address_filename = "address.rb"
|
21
21
|
top_level_filename = "generated_from_json.rb"
|
22
|
-
phonenumbers_filename = "
|
22
|
+
phonenumbers_filename = "phone_numbers.rb"
|
23
23
|
|
24
24
|
expected_address = File.readlines(address_filename).join.chomp # trim off any trailing whitespace (irrelevent for this test)
|
25
25
|
expected_example = File.readlines(top_level_filename).join.chomp # trim off any trailing whitespace (irrelevent for this test)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: class_from_son
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Morrisby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This gem will attempt to generate code of a class of an object representing
|
14
14
|
the contents of a Serialised-Object-Notation (SON) string (or file). E.g. it will
|
@@ -22,7 +22,7 @@ files:
|
|
22
22
|
- README.md
|
23
23
|
- lib/class_from_SON.rb
|
24
24
|
- test/test_class_from_son.rb
|
25
|
-
homepage: https://
|
25
|
+
homepage: https://github.com/RMorrisby/class_from_son
|
26
26
|
licenses:
|
27
27
|
- MIT
|
28
28
|
metadata: {}
|