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

Move builder methods withText and withXml to their own traits #6

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

hosamaly
Copy link
Contributor

@hosamaly hosamaly commented Mar 26, 2018

  • Move builder methods withText and withXml to their own traits
  • Add DocDataBuilder#withDocId(String) and BodyBuilder#withEnd(BodyEnd)
  • Accept an optional TitleType in HeadBuilder#withTitle
  • Implement an AbstractBuilder and a MediaCaptionBuilder

These can go into a release, and then a separate release can be made for:

  • Deprecate MixedContentBuilder#withXml

It wasn't included in the actual `libraryDependencies` so this change
has no effect on the dependency structure.
Grouping all builder traits together
…nd)`

Additionally, make `DocDataBuilder#withDocDataOption` `protected` in line
with other helper methods for easier extensibility.

Finally, print the schema version in the `TwoWaySpec` test.
Introduce `MixedContentBuilder` and `AnyContentBuilder` to encapsulate
these methods.

`MediaReferenceBuilder` now extends `MixedContentBuilder`.

`AnyContentBuilder` is not used in this code base but an example in its
docs shows how to use it.
It's not safe. The caller can inject any XML that doesn't match the schema.

In all builders of mixed-content objects, values are appended to the
element. Combining these methods with `withText`, all forms of valid XML
can be generated.
@@ -42,6 +43,31 @@ trait Builder[T] {
override def toString: String = build.toString
}

trait BlockContentBuilder {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This class was moved from line 155.

def withNitfTable(x: NitfTable): this.type = withBlockContent(x)
def withSubordinateHeadline(x: Hl2): this.type = withBlockContent(x)

def withTextParagraph(x: String, markAsSummary: Boolean = true): this.type = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a new helper method in this class. It used to exist as BodyHeadBuilder#withAbstract(String, Boolean).

@@ -62,26 +88,66 @@ trait EnrichedTextBuilder {
def withObjectTitle(x: ObjectTitle): this.type = withEnrichedText(x)
def withPronunciation(x: Pronounce): this.type = withEnrichedText(x)
def withVirtualLocation(x: Virtloc): this.type = withEnrichedText(x)
def withXml(x: NodeSeq): this.type = withContent(dataRecord(x))
def withText(x: String): this.type = withContent(dataRecord(x))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This two methods moved into MixedContentBuilder and AnyContentBuilder.

}

class BodyHeadBuilder(var build: BodyHead = BodyHead()) extends Builder[BodyHead] {
def withByline(x: String): this.type = withByline(Byline(Seq(dataRecord(x))))
def withHeadline(x: String): this.type = withHeadline(new HeadlineBuilder().withPrimaryHeadline(x))
def withAbstract(x: NodeSeq): this.type = withAbstract(Abstract(Seq(dataRecord(x))))
Copy link
Contributor Author

@hosamaly hosamaly Mar 26, 2018

Choose a reason for hiding this comment

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

This method was removed in line with the deprecation of withXml.

* val xml = scalaxb.toXML(nitf, None, None, toScope(Some("my") -> "http://www.example.com/my-extension"))
* }}}
*/
trait AnyContentBuilder { this: Builder[_ <: { def any: Seq[scalaxb.DataRecord[Any]] }] =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Codacy complains about the structural type expression here. However, I don't think there is anything wrong with it. We're not accessing any of the fields of the Builder, and the generic type is erased at runtime anyway.

@deprecated("Use multiple invocations of other methods for a type-safe approach", since = "3.x.3")
def withXml(x: NodeSeq): this.type = withContent(dataRecord(x))

protected def withContent(x: DataRecord[_]): this.type
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the implementation is the same every time this trait is extended. Worth providing it as a default implementation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wish I could! Because the implementation calls .copy, I don't think it's possible to do this other than with a macro.

Do you know of another way to do it?

Copy link
Contributor

Choose a reason for hiding this comment

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

I saw it too late 😩 I suppose you could define an abstract class inheriting from Builder and MixedContentBuilder? That may not be very elegant though...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even if I did this, I still won't be able to implement withContent. That's because case classes' .copy() is not defined in a trait.

@@ -32,7 +32,7 @@ class BuildersSpec extends FunSpec {
.withHead(new BodyHeadBuilder()
.withHeadline("News Article")
.withByline("It took a lot of work to get there")
.withAbstract(<p>It wasn't easy, but they <em>never</em> gave up!</p>)
.withAbstract(new AbstractBuilder().withTextParagraph("It wasn't easy, but they never gave up!"))
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose you had to remove the em to avoid having to parse the input string. Any chance the input will ever contain tags and/or references?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the <em> because I removed/deprecated the methods that accept XML.

The input can still contain an em, except we'd expect it to be added, type-safely, like this:

.withAbstract(new AbstractBuilder()
  .withParagraph(new ParagraphBuilder()
    .withText("It wasn't easy, but they ")
    .withEmphasis(Em(Seq(dataRecord("never"))))
    .withText(" gave up!")
  )
)

In another project, I intend to create a utility that converts Jsoup nodes to NITF nodes so that we can parse HTML and convert it to NITF.

Copy link
Contributor

@regiskuckaertz regiskuckaertz left a comment

Choose a reason for hiding this comment

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

Great as soon as the build passes 👍

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.

None yet

2 participants