Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to encode ProjectSpec to JSON #545

Merged
merged 8 commits into from
Apr 22, 2019

Conversation

ryohey
Copy link
Collaborator

@ryohey ryohey commented Mar 26, 2019

I first tried to implement spec generation, but as you mentioned, I needed to be able to serialize ProjectSpec. #9 (comment)

I defined JSONDictionaryEncodable protocol like JSONObjectConvertible of JSONUtilities, and implemented it in ProjectSpec and related classes. I did not use Codable because some classes do not have a simple correspondence with the JSON structure.

I wrote a test that encodes ProjectSpec into JSON and decodes back and to test if they are equal. However, it may not be perfect because the tests do not cover all patterns and implementations are written by a lot of manual work.

fixes #123

@ryohey ryohey requested a review from yonaskolb March 26, 2019 15:02
Copy link
Owner

@yonaskolb yonaskolb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @ryohey!
Having Decodable objects would be nice, but this is a great start! 👍

}

if targets.count > 0 {
dict["targets"] = targets
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these if array.count > 0 { are not really required. It might be useful for some use cases to generate out all the empty arrays. For the compact spec you have now, there could be a function JSONDictionary.removeEmptyArrays that loops through and removes all empty arrays

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitively a good approach generating empty template really help getting started.

if let watchOS = watchOS {
dict["watchOS"] = watchOS.string
}
if let macOS = macOS {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these if statements for optional values could be removed if the dictionary was [String: Any?].


public protocol JSONDynamicEncodable {
// returns JSONDictionary or JSONArray or JSONRawType
func toJSONValue() -> Any
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we need all these protocols as they aren't really used on their own. I think all the functions could just be the func toJSONValue() -> Any. Maybe just the top level spec would have a function that returned a dictionary.

func testJSONEncodable() {
describe {
$0.it("encodes to json") {
let proj = Project(basePath: Path.current,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice object 😄 This might be useful for other tests

ryohey added a commit to ryohey/XcodeGen that referenced this pull request Apr 4, 2019
ryohey added a commit to ryohey/XcodeGen that referenced this pull request Apr 4, 2019
@ryohey
Copy link
Collaborator Author

ryohey commented Apr 5, 2019

@yonaskolb Thank you for your reviewing! I fixed them up. As you said, It would be nice to add the process of removing nil and empty arrays / dictionaries in the process of generating JSON for human reading.

@ryohey ryohey requested a review from yonaskolb April 6, 2019 09:22
]

if optional {
dict["optional"] = true
Copy link
Owner

@yonaskolb yonaskolb Apr 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit worried about the maintainability of all these properties, and that regressions might occur in the future by accident.

To aid with the properties that have defaults, and because we're now mapping those defaults in 3 places (property init, decoding, and now encoding), it would be good if we have static properties for all of these. In this example:

static let optionalDefault = false

This this check would be

if optional != optionalDefault {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yonaskolb It's make sense. Since I changed it, could you please review it?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Could you please rebase to fix the merge conflict and add a changelog?

randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? false
parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? false
randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? Scheme.Test.TestTarget.randomExecutionOrderDefault
parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? Scheme.Test.TestTarget.parallelizableDefault
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor and doesn't need to change, but not sure you need to traverse the whole namespace path, I think you can just use TestTarget.parallelizableDefault

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
After trying it out, it seems necessary to specify the complete namespace in the extension.

@ryohey ryohey force-pushed the projectspec-json branch from d5645ea to ea6fb60 Compare April 20, 2019 03:24
@ryohey
Copy link
Collaborator Author

ryohey commented Apr 20, 2019

@yonaskolb Thank you for your review! I rebased it and fix conflicts, added changelog.

@yonaskolb
Copy link
Owner

Thanks @ryohey! Not sure how you want to follow this PR up and how it will be used (you mentioned project migration), but I think it would be useful having a parameter like Project.toDictionary(style: ProjectEncodingStyle) that does the empty array and dictionary removal

enum ProjectEncodingStyle {
  /// removes empty dictionaries and arrays
  case minimal
  case full
}

Feel free to do that here or in another PR. Perhaps would be better here

@ryohey
Copy link
Collaborator Author

ryohey commented Apr 22, 2019

@yonaskolb Thanks! I received a pull-request from @AndreiVidrasco that adds feature to filter out empty values from dictionary. and we talked about this pr #545. So I merge this pr this time.
@AndreiVidrasco I would like you to make a pull-request that reflects this conversation #545 (comment)

@ryohey ryohey merged commit cd669ee into yonaskolb:master Apr 22, 2019
@ryohey ryohey deleted the projectspec-json branch April 22, 2019 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Serialize ProjectSpec to JSON
3 participants