Packages

trait Factory[Output] extends Serializable

A factory to create new instances, especially dynamic mix-ins.

Author:

杨博 (Yang Bo) <[email protected]>

Source
Factory.scala
Examples:
  1. Given a trait that has abstract members.

    trait Foo {
      val myValue: String
      var myVariable: Long
      def myMethod0(): Option[Double]
      def myMethod2(p0: Int, p1: Int): Int
      def myCurriedMethod(seq: Seq[Int])(mapper: Int => String): Seq[String]
    
      // Methods without pararmeters is disabled for now, due to https://github.com/scala/bug/issues/10647
      // def myByNameMethod: Option[Int]
    }

    When creating a factory for the trait.

    val factory = Factory[Foo]

    Then the newInstance method of the factory should accept named arguments according to abstract members.

    val createdFromNamedArguments: Foo = factory.newInstance(
      myValue = "string value",
      myVariable = 42L,
      myMethod0 = () => Some(0.5),
      myMethod2 = _ + _,
      myCurriedMethod = seq => mapper => seq.map(mapper)
    )
    createdFromNamedArguments.myValue should be("string value")
    createdFromNamedArguments.myVariable should be(42L)
    
    createdFromNamedArguments.myMethod0() should be(Some(0.5))
    createdFromNamedArguments.myMethod0() shouldNot be theSameInstanceAs createdFromNamedArguments.myMethod0()
    
    createdFromNamedArguments.myMethod2(1000, 24) should be(1024)
    
    createdFromNamedArguments.myCurriedMethod(Seq(2, 3, 4))(_.toString) should be(Seq("2", "3", "4"))

    When using unnamed parameters, the parameters should be passed in alphabetical order

    val createdFromUnnamedArguments: Foo = factory.newInstance(
      seq => mapper => seq.map(mapper), // myCurriedMethod
      () => Some(0.5),                  // myMethod0
      _ + _,                            // myMethod2
      "string value",                   // myValue
      42L                               // myVariable
    )
  2. ,
  3. Given two traits that have no abstract member.

    trait Foo
    trait Bar

    When creating a factory for mix-in type of the two types.

    val factory = Factory[Foo with Bar]

    Then the newInstance method of the factory should accept no parameters.

    val fooBar: Foo with Bar = factory.newInstance()
    fooBar should be(a[Foo])
    fooBar should be(a[Bar])
  4. ,
  5. Given a trait that contains an abstract method annotated as @inject.

    import com.thoughtworks.feature.Factory.inject
    trait Foo[A] {
      @inject def orderingA: Ordering[A]
    }

    When creating a factory for the trait

    val factory = Factory[Foo[Int]]

    Then the @inject method will be replaced to an implicit value.

    val foo = factory.newInstance()
    foo.orderingA should be(implicitly[Ordering[Int]])

    It will not compile if no implicit value found. For example, Foo[Symbol] requires an implicit value of type Ordering[Symbol], which is not availble.

    "Factory[Foo[Symbol]]" shouldNot compile

    If the trait does not contain abstract methods other than @inject methods, then the factory type class is a Factory.Factory0, which can be summoned by Predef.implicitly,

    val nullaryFactory = implicitly[Factory.Factory0[Foo[Int]]]

    and newInstance method is available on the Factory.Factory0 as well.

    nullaryFactory.newInstance().orderingA should be(implicitly[Ordering[Int]])
Note

However, if the nested type is an alias to another type outside of the type to create, then it is allowed

trait Outer {
  type Inner = String
  val inner: Option[Inner]
}

val outer: Outer = Factory[Outer].newInstance(inner = Some("my value"))
outer.inner should be(Some("my value"))
,

This Factory disallows creating types that has an abstract member whose type depends on nested types. Given an abstract val inner whose type is the Inner,

trait Outer {
  trait Inner
  val inner: Option[Inner]
}

then the attempt to create factory for Outer, like Factory[Outer].newInstance(inner = None), will cause a value inner has incompatible type compile error.

,

@inject works on implicit abstract methods as well.

import com.thoughtworks.feature.Factory.inject
trait Foo[A] {
  @inject implicit def orderingA: Ordering[A]
}
Factory[Foo[Int]].newInstance().orderingA should be(implicitly[Ordering[Int]])
,

Factories may be nested

import com.thoughtworks.feature.Factory.inject
import com.thoughtworks.feature.Factory.Factory1
import com.thoughtworks.feature.ByName.`=>`
trait Outer {
  trait AbstractParameterApi
  type AbstractParameter <: AbstractParameterApi

  trait InnerApi {
    def foo: AbstractParameter
  }
  type Inner <: InnerApi

  @inject val innerFactory: Factory1[`=>`[AbstractParameter], Inner]
}

val outer = Factory[Outer].newInstance()
outer.innerFactory.newInstance(new outer.AbstractParameterApi {}) should be(an[outer.Inner])
,

Factories may create types that contains refinement types

trait SomeBuilder {
  type A
  def makeSome(a: A) = Some(a)
}
val someBuilder = Factory[SomeBuilder { type A = Int }].newInstance()
someBuilder.makeSome(42) should be(Some(42))
Linear Supertypes
Type Hierarchy
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. Factory
  2. Serializable
  3. Serializable
  4. AnyRef
  5. Any
Implicitly
  1. by any2stringadd
  2. by StringFormat
  3. by Ensuring
  4. by ArrowAssoc
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Type Members

  1. abstract type Constructor

    A function type that returns Output.

    A function type that returns Output.

    The parameter types are all abstract members in Output

Abstract Value Members

  1. abstract val newInstance: Constructor

    Returns an instance of Output, which overrides abstract members in Output according to parameters pass to this newInstance method.

Concrete Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##(): Int
    Definition Classes
    AnyRef → Any
  3. def +(other: String): String
    Implicit
    This member is added by an implicit conversion from Factory[Output] to any2stringadd[Factory[Output]] performed by method any2stringadd in scala.Predef.
    Definition Classes
    any2stringadd
  4. def ->[B](y: B): (Factory[Output], B)
    Implicit
    This member is added by an implicit conversion from Factory[Output] to ArrowAssoc[Factory[Output]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc
    Annotations
    @inline()
  5. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  6. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  7. def clone(): AnyRef
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @native() @throws( ... )
  8. def ensuring(cond: (Factory[Output]) ⇒ Boolean, msg: ⇒ Any): Factory[Output]
    Implicit
    This member is added by an implicit conversion from Factory[Output] to Ensuring[Factory[Output]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  9. def ensuring(cond: (Factory[Output]) ⇒ Boolean): Factory[Output]
    Implicit
    This member is added by an implicit conversion from Factory[Output] to Ensuring[Factory[Output]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  10. def ensuring(cond: Boolean, msg: ⇒ Any): Factory[Output]
    Implicit
    This member is added by an implicit conversion from Factory[Output] to Ensuring[Factory[Output]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  11. def ensuring(cond: Boolean): Factory[Output]
    Implicit
    This member is added by an implicit conversion from Factory[Output] to Ensuring[Factory[Output]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  12. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  13. def equals(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  14. def finalize(): Unit
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( classOf[java.lang.Throwable] )
  15. def formatted(fmtstr: String): String
    Implicit
    This member is added by an implicit conversion from Factory[Output] to StringFormat[Factory[Output]] performed by method StringFormat in scala.Predef.
    Definition Classes
    StringFormat
    Annotations
    @inline()
  16. final def getClass(): Class[_]
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  17. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  18. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  19. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  20. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  21. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  22. final def synchronized[T0](arg0: ⇒ T0): T0
    Definition Classes
    AnyRef
  23. def toString(): String
    Definition Classes
    AnyRef → Any
  24. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  25. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  26. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @throws( ... )
  27. def [B](y: B): (Factory[Output], B)
    Implicit
    This member is added by an implicit conversion from Factory[Output] to ArrowAssoc[Factory[Output]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc

Inherited from Serializable

Inherited from Serializable

Inherited from AnyRef

Inherited from Any

Inherited by implicit conversion any2stringadd from Factory[Output] to any2stringadd[Factory[Output]]

Inherited by implicit conversion StringFormat from Factory[Output] to StringFormat[Factory[Output]]

Inherited by implicit conversion Ensuring from Factory[Output] to Ensuring[Factory[Output]]

Inherited by implicit conversion ArrowAssoc from Factory[Output] to ArrowAssoc[Factory[Output]]

Ungrouped