1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# ............................................................................................... #
#
# Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# ............................................................................................... #

----
This module defines an AdapterFabric helper.
----
module gololang.Adapters

struct adapter = {
  definition
}

----
Adapter augmentations.
----
augment gololang.Adapters.types.adapter {

  ----
  Defines interface(s) for the Adapter:

  * parameter(s): a tuple of strings,
  * returns the adapter.

  Usage:

      let runnerAdapter = Adapter()
        : interfaces(["java.io.Serializable", "java.lang.Runnable"])
  ----
  function interfaces = |this, interfacesTuple| {
    this: definition(): put("interfaces", interfacesTuple)
    return this
  }

  ----
  Provides a method implementation

  * parameters: a method name, an implementation function
  * returns the adapter.

  Usage:

      let result = array[1,2,3]

      let runnerAdapter = Adapter()
        : interfaces(["java.io.Serializable", "java.lang.Runnable"])
        : implements("run", |this| {
            for (var i = 0, i < result: length(), i = i + 1) {
              result: set(i, result: get(i) + 10)
            }
          })
  ----
  function implements = |this, methodName, closure| {
    this: definition(): get("implements"): put(methodName, closure)
    return this
  }

  ----
  Specifies the name of the parent class (`java.lang.Object` by default).

  * parameter: parent class name
  * returns the adapter.

  Usage:

      let arrayListAdapter = Adapter()
        : extends("java.util.ArrayList")
  ----
  function extends = |this, className| {
    this: definition(): put("extends", className)
    return this
  }

  ----
  Provides a method override.

  * parameters: method name and an implementation function
  * returns the adapter.

  Usage:

      let objectAdapter = Adapter()
        : overrides("toString", |super, this| -> ">>> " + super(this))

      println(objectAdapter: newInstance(): toString())

  This prints something like: `>>> $Golo$Adapter$0@2aaf7cc2`.
  ----
  function overrides = |this, methodName, closure| {
    this: definition(): get("overrides"): put(methodName, closure)
    return this
  }

  ----
  Returns an instance based on a configuration
  (see also [`adapter: definition()`](#adapter)).
  ----
  function maker = |this| {
    return AdapterFabric(): maker(this: definition())
  }

  ----
  Returns an instance of the adapted Java class.

  Usage:

      let result = array[1,2,3]

      let runnerAdapter = Adapter()
        : interfaces(["java.io.Serializable", "java.lang.Runnable"])
        : implements("run", |this| {
            for (var i = 0, i < result: length(), i = i + 1) {
              result: set(i, result: get(i) + 10)
            }
          })

      let runner = runnerAdapter: newInstance()

      runner: run()
  ----
  function newInstance = |this| {
    return this: maker(): newInstance()
  }

  ----
  Returns an instance of the adapted Java class.

  The parameters are the parameters of the base class constructor.
  ----
  function newInstance = |this, args...| {
    return this: maker(): newInstance(args)
  }
}

----
Adapter constructor.
----
function Adapter = {
  let adapterInstance = adapter(map[])
  adapterInstance: definition(): put("extends", "java.lang.Object")
  adapterInstance: definition(): put("implements", map[])
  adapterInstance: definition(): put("overrides", map[])
  return adapterInstance
}