-
Notifications
You must be signed in to change notification settings - Fork 437
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
Kiwi image editor: Improve #to_xml to decrease the resulting diff #4002
Conversation
ChrisBr
commented
Oct 12, 2017
- Only write the default package group
- Write package group & repositories on same position as before
Codecov Report
@@ Coverage Diff @@
## master #4002 +/- ##
=========================================
- Coverage 89.22% 89.2% -0.03%
=========================================
Files 309 309
Lines 18228 18235 +7
=========================================
+ Hits 16264 16266 +2
- Misses 1964 1969 +5
|
Codecov Report
@@ Coverage Diff @@
## master #4002 +/- ##
==========================================
- Coverage 89.18% 89.11% -0.07%
==========================================
Files 309 310 +1
Lines 18236 18416 +180
==========================================
+ Hits 16264 16412 +148
- Misses 1972 2004 +32
|
For codecov, you can try change the class definition from this: class Kiwi::Image to this: module Kiwi
class Image I think that might be why codecov isn't working for these files.. Also make the same change to |
src/api/app/models/kiwi/image.rb
Outdated
|
||
# Reparser for pretty printing | ||
Nokogiri::XML(doc.to_xml, &:noblanks).to_xml | ||
Nokogiri::XML(doc.to_xml, &:noblanks).to_xml(indent: kiwi_indentation(doc)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering, would it be possible to use a .xml.builder view to generate this xml? Instead of Nokogiri and xpath? I'm finding it quite hard to read this code..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the indent parameter to doc.to_xml wouldn't have the same effect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bgeuken would need to try that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evanrolfe Which part do you mean? I doesn't seem that complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole method is hard to understand IMO, there are too many things going on. Its doing two things:
- Deciding which things should go in the XML document.
- Deciding how the XML document should be structured.
I think we should separate those two concerns just like how we separate models from views.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. I think we should move some code to separate methods, like setting kiwi_body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to a dedicated Kiwi::Image::ToXml class!
src/api/app/models/kiwi/image.rb
Outdated
@@ -157,6 +158,15 @@ def self.binaries_available(project, use_project_repositories, repositories) | |||
|
|||
private | |||
|
|||
def kiwi_indentation(xml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I really like having this in the model here. It looks like view logic to me.. I think we should start to think about seperating the business logic about kiwi images from the view logic about xml output. At the very least we could extract the xml presentation stuff into its own class like Kiwi::Image::ToXml
or Kiwi::Image::XmlFormatter
etc.
@evanrolfe see #4010 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM
src/api/app/models/kiwi/image.rb
Outdated
# for now we only write the default package group | ||
xml_packages = default_package_group.to_xml | ||
packages = doc.xpath('image/packages[@type="image"]').first | ||
packages ? packages.replace(xml_packages) : image.last_element_child.after(xml_packages) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not an if ... else ... end
?? This is a little bit hard to understand because is not used to assign the value to anything and this is running methods instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this explicitly tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
Yes, I use one time the DEFAULT_KIWI_BODY (without packages and repositories) and the one time the kiwi_xml provided from include_context 'a kiwi image xml'
which already contains packages and repositories!
src/api/app/models/kiwi/image.rb
Outdated
|
||
previous = doc.xpath("image/repository").first.try(:previous) || image.last_element_child |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to use another name for this variable... something like repository_position
because in the case of the image.last_element_child
this is not the previous node of anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this explicitly tested?
src/api/app/models/kiwi/image.rb
Outdated
@@ -157,6 +158,15 @@ def self.binaries_available(project, use_project_repositories, repositories) | |||
|
|||
private | |||
|
|||
def kiwi_indentation(xml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are basing this calculation in the space between the image tag and the first child inside it... what if this is not well indented? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this is best effort. If the file is not well indented, we don't have any chance to fix it, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe calculating the average of the indentation could be more closer... but anyway, is up to you to do that effort.
src/api/app/models/kiwi/image.rb
Outdated
@@ -157,6 +158,15 @@ def self.binaries_available(project, use_project_repositories, repositories) | |||
|
|||
private | |||
|
|||
def kiwi_indentation(xml) | |||
content = xml.xpath('image').children.first.try(:content) | |||
if content |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case I would use the ternary operator ?
, because you are returning a value, no running a method like in my other comment about using an if else end
in kiwi editor. Because for now we only allow to edit the default package group. Writing all package groups always would create a big diff.
to minimize the diff.
to minimize the generated diff.
b29bfcc
to
ff420c0
Compare
@mdeniz @evanrolfe @DavidKang @bgeuken Please review again
Also talked with @adrianschroeter about the indentation: We will keep reading the first element for now. Introducing a diff without whitespace would be complicated and also introduce some new problems (e.g. when using which diff and also possible introduction of not wanted errors). Also hardcoding is not wanted. If the first element is wrong indented, the user has to deal with it for now! |
src/api/app/models/kiwi/to_xml.rb
Outdated
@@ -0,0 +1,89 @@ | |||
# TODO: Please overwrite this comment with something explaining the model target | |||
module Kiwi | |||
class ToXml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Nitpick] Minor point but can you make it clear that this is for converting a Kiwi::Image to xml? i.e. like:
module Kiwi
class Image
class ToXml
or
module Kiwi
class ImageToXml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad naming (using a verb + a noun), I would prefer something like Kiwi::Image::Xml
and instead of a class I also prefer to use a module to include in the Kiwi::Image
class. That way you don't need to have the to_xml
twice and also no need to instanciate an object.
If you stil prefer a class then use class methods, no need to create an instance of a class without any internal state, just the image reference, also because you aren't reusing this class in any way.
And also you will need to test this module/class alone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me I prefer to use a class to model complex operations like this instead of a module with methods. I dont really see a problem with having to instantiate an instance of ToXml..
IMO a class is a much more powerful tool for modelling the behaviour of Image#to_xml than a set of methods in a module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed on the naming! Either module or class I don't have a strong preference.
@mdeniz regarding the tests: atm this class is already implicit tested by the image specs. We can refactor this in a later PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many times it is going to be used codewise? just one... no need to instanciate an object if you don't want to use the internal state too. I don't like it as it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many times it is going to be used codewise? just one...
I don't see how that makes any difference?
no need to instanciate an object if you don't want to use the internal state too.
This is a class which outputs xml based on a kiwi image so the internal state is the kiwi image. Do you really think that putting a bunch of methods into a file is better than having a class to model behaviour? Are we Ruby developers or C developers? :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regarding the tests: atm this class is already implicit tested by the image specs.
Yeah I agree. We are testing the behaviour of Kiwi::Image overall, so the tests shouldn't care if this code is in a class or a module or whatever..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how that makes any difference?
This is a class which outputs xml based on a kiwi image so the internal state is the kiwi image. Do you really think that putting a bunch of methods into a file is better than having a class to model behaviour?
I'm not talking about using a module but at least using a class method instead of an instance method, if the internall state is not changing why do we need an instance for it? is just a decorator method... so no need to have an object living for exporting one xml string based on the image.
Are we Ruby developers or C developers? :P
I'm a developer... not tied to any language 🗡
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the internall state is not changing why do we need an instance for it?
Because you can write code that is much more readable and easier to work with if you consider that the image is the internal state. The fact that it never changes doesn't matter.
so no need to have an object living for exporting one xml string based on the image.
Yes you're right theres no need to have an object for this, you can do it just fine with a method in a module or a class method, but the code will be much better if you use a object and instance methods for this. If you can save then state to a instance variable then that means you don't have to always pass the image around from one method to another.
Here are more reasons why we should not use a class method for this. Before you say "but you can find a blog post on the internet to support any claim you have about programming!", I tried to find anything supporting class methods for this kind of thing but could not..
http://blog.codeclimate.com/blog/2012/11/14/why-ruby-class-methods-resist-refactoring/
http://old.mlomnicki.com/programming/ruby/2011/07/20/class-vs-instance-methods.html
I'm a developer... not tied to any language 🗡️
Good answer 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, anyway. At least change that name... is horrible 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. One nitpick but otherwise I think it looks much better now that the xml stuff is in its own class, thanks!
src/api/app/models/kiwi/to_xml.rb
Outdated
@@ -0,0 +1,89 @@ | |||
# TODO: Please overwrite this comment with something explaining the model target | |||
module Kiwi | |||
class ToXml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad naming (using a verb + a noun), I would prefer something like Kiwi::Image::Xml
and instead of a class I also prefer to use a module to include in the Kiwi::Image
class. That way you don't need to have the to_xml
twice and also no need to instanciate an object.
If you stil prefer a class then use class methods, no need to create an instance of a class without any internal state, just the image reference, also because you aren't reusing this class in any way.
And also you will need to test this module/class alone.
|
||
context 'with a kiwi file with packages and repositories' do | ||
let(:package) { create(:package) } | ||
let(:kiwi_image) { Kiwi::Image.build_from_xml(kiwi_xml, 'some_md5') } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to have a factory for it?
|
||
context 'with a kiwi file without packages and repositories' do | ||
let(:package) { create(:package) } | ||
let(:kiwi_image) { Kiwi::Image.build_from_xml(Kiwi::Image::DEFAULT_KIWI_BODY, 'some_md5') } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to have a factory for it?
src/api/app/models/kiwi/to_xml.rb
Outdated
return nil unless kiwi_file | ||
@image.package.source_file(kiwi_file) | ||
else | ||
Kiwi::Image::DEFAULT_KIWI_BODY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a guard clause instead?
def kiwi_body
return Kiwi::Image::DEFAULT_KIWI_BODY unless @image.package
kiwi_file = @image.package.kiwi_image_file
return nil unless kiwi_file
@image.package.source_file(kiwi_file)
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
ff420c0
to
6591753
Compare
src/api/app/models/kiwi/image/xml.rb
Outdated
#### To define class methods as private use private_class_method | ||
#### private | ||
|
||
#### Instance methods (public and then protected/private) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you get rid of these comments because this is not an ActiveRecord model so they don't make sense here..
does not alter the xml to decrease the resulting diff.
22f4adb
to
a12a5be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Does it have more sense to ename Kiwi::Image::Xml#to_xml
method as to_s
??