Основы jc
В этой главе описаны основные принципы работы и скрипты jc
.
Подготовка
Для начала создадим пустой каталог и в нем файл project.jc
со следующим содержимым:
import jandcode.jc.*
import jandcode.jc.std.*
class P1 extends ProjectScript {
void onInclude() {
project.name = "tutorial-1"
include(Utils)
include(Utils).with {
param1 = "NewValue1"
}
include(Utils).param2 = "Val2"
Utils u = getIncluded(Utils)
if (u != null) {
u.param3 = "Q3"
}
include(Showlibs)
cm.add("one", "Первая команда") {
log("Команда 1 выполнена")
}
cm.add("two", "Вторая команда", this.&cmTwo,
cm.opt("a", "Опция a"),
cm.opt("b", "", "Опция b с параметром"),
)
}
void cmTwo(CmArgs args) {
ant.echo(message: "Arguments: ${args}")
println("Печатаем текст")
log("Команда 2 выполнена")
}
//////
public static class Utils extends ProjectScript {
String param1 = "value1"
String param2 = "value2"
String param3 = "value3"
void onInclude() {
cm.add("util-one", "Первая команда из утилит") {
showParam()
log("Команда util-one выполнена")
}
}
void showParam() {
log "Param1=${param1}"
log "Param2=${param2}"
log "Param3=${param3}"
}
}
}
Запустим приложение jc
в этом каталоге и увидим список команд.
Выполним команду two
:
jc two -b:1 -a
Далее будут описаны все понятия, которые в этом скрипте использованы.
Описание
project.jc
(как и любой другой .jc
файл) - это groovy
файл.
В нем должен быть определен класс с любым именем, который является
наследником от jandcode.jc.ProjectScript
. В этом классе
должен быть определен метод onInclude()
, который и будет выполнен
при загрузке такого файла.
Пример минимального project.jс
:
import jandcode.jc.*
class EmptyProject extends ProjectScript {
void onInclude() {
}
}
Так как это обычный groovy
-класс, то он прекрасно редактируется в IDE с поддержкой
groovy
, только необходимо настроить IDE так, что бы она воспринимала файлы
с расширением .jc
как groovy
-файлы. Соответственно доступны все удобства IDE,
такие как автодополнение, переход на объявление и т.д.
В .jc
-файлах полностью отсутствует какая-либо синтаксическая или поведенческая магия,
это просто класс. Это нужно помнить при разработке скриптов.
Процесс загрузки jc
Для начала jc
создает экземпляр проекта для текущего каталога. Текущий каталог
становится свойством проекта. Сам проект является экземпляром
класса jandcode.jc.Project
. Далее под проектом будет пониматься именно
этот экземпляр.
Затем файл project.jc
загружается и создается экземпляр класса
jandcode.jc.ProjectScript
, который в этом файле описан. Далее экземпляры
такого класса будут называтся скриптами.
Затем скрипту передается ссылка на проект и у скрипта вызывается метод
onInclude
.
Проект и скрипт
Для одного экземпляра проекта можно выполнить несколько скриптов, но каждый экземпляр скрипта принадлежит только одному проекту.
У скрипта имеется ссылка на проект, для которого он предназначен. Кроме того,
скрипт реализует интерфейс проекта jandcode.jc.Project
, делегируя все методы
проекта проекту.
Иллюстрация:
import jandcode.jc.*
class ProjectInScript extends ProjectScript {
void onInclude() {
// текущий проект
Project p1 = getProject()
// это groovy, можно писать и так:
Project p2 = project
// получение имени проекта
String s1 = project.getName()
String s2 = project.name
// скрипт делегирует методы интерфейса
// jandcode.jc.Project проекту,
// поэтому можно писать и так:
String s3 = getName()
String s4 = name
// а это получение пути относительно
// рабочего каталог проекта (workdir, wd):
String wd1 = project.wd("temp")
String wd2 = wd("temp")
}
}
include
У проекта имеется метод include(script)
.
Это механизм выполнения скриптов в контексте проекта. В качестве скрипта можно указать
класс скрипта, полное имя класса скрипта или имя файла со скриптом:
// класс скрипта
project.include(jandcode.jc.std.Showlibs)
// класс скрипта, пакет должен быть импортирован
project.include(Showlibs)
// полное имя класса скрипта
project.include("jandcode.jc.std.Showlibs")
// имя файла со скриптом
project.include("./my-script.jc")
Помните, что скрипт делегирует все методы проекта проекту? Поэтому можно писать и так:
// класс скрипта
include(jandcode.jc.std.Showlibs)
// класс скрипта, пакет должен быть импортирован
include(Showlibs)
// полное имя класса скрипта
include("jandcode.jc.std.Showlibs")
// имя файла со скриптом
include("./my-script.jc")
Метод include
работает так:
- для начала проверяется, не был ли выполнен
include
в проекте ранее для этого скрипта. Если уже выполнялся, то возвращается экземпляр ранее выполненного скрипта. - создается экземпляр скрипта (
jandcode.jc.IProjectScript
) - экземпляру скрипта передается ссылка на проект
- у экземпляра скрипта вызывается метод
onInclude()
- метод кеширует экземпляр скрипта и возвращет его в качестве результата
работы функции
include
Таком образом:
- один и тот же скрипт можно включить в проект только один раз
- можно получить экземпляр скрипта, ранее включенного в проект
Иллюстрация:
// включаем скрипт первый раз, создается экземпляр JavaProject
JavaProject jm = include(jandcode.jc.std.JavaProject)
// включаем скрипт второй раз, не создается JavaProject,
// просто возвращается предыдущий
JavaProject jm2 = include(jandcode.jc.std.JavaProject)
Имеется возможность проверить, был ли включен скрипт в проект (метод getIncluded()
):
// еще не включали
JavaProject jm = getIncluded(JavaProject)
assert jm == null
// включаем
include(JavaProject)
jm = getIncluded(JavaProject)
assert jm != null
with
В groovy
есть метод with
, который позволяет выполнить closure
в контексте
конкретного объекта. Это позволяет сократить код и сделать его более наглядным:
class Data {
String f1
String f2
}
def d = new Data()
d.with {
f1 = '1'
f1 = '2'
}
// эквивалентный код без with:
d.f1 = '1'
d.f2 = '2'
В jc
этот метод обычно используются для настройки конкретных скриптов в момент
их включения в проект:
include(SomeScript).with {
someProperty1 = 1
someMethod2(1)
}
// эквивалентный код без with:
SomeScript sm = include(SomeScript)
sm.someProperty1 = 1
sm.someMethod2(1)
// можно и так:
include(SomeScript).someProperty1 = 1
include(SomeScript).someMethod2(1)
Методы в скриптах
Так как скрипт - это обычный класс, нет никаких ограничений на методы в этом классе. Можно объявлять любые нужные вам методы и конечно внутренние классы.
Команды
Команда - это closure
, которая имеет имя, описание и опции. Команда является
экземпляром класса jandcode.jc.Cm
.
Объявление команды должно быть в методе onInclude()
, так как только он непосредственно
выполняется ядром jc
.
У проекта имеется метод getCm()
, который возвращает хранилище команд проекта и средства
их определения.
Примеры объявления команд:
import jandcode.jc.*
class CmInScript extends ProjectScript {
void onInclude() {
/* объявление команды 'cm1', без описания.
код команды - closure
*/
cm.add("cm1") {
log("Команда выполнена")
}
/* объявление команды 'cm2', с описанием.
код команды - closure
*/
cm.add("cm2", "Это команда 2\nОписание может быть\nмногострочным") {
log("Команда выполнена")
}
/* объявление команды 'cm3', с описанием.
код команды - метод cmMethod
*/
cm.add("cm3", this.&cmMethod, "Это команда 3")
/* объявление команды 'cm4', с описанием и опциями.
код команды - метод cmMethod
*/
cm.add("cm3", this.&cmMethod, "Это команда 3",
cm.opt("opt1", false, "boolean опция"),
cm.opt("opt2", "Также boolean опция"),
cm.opt("opt3", "", "Опция с параметром"),
)
}
/**
* Для методов, котрые используются как команды,
* можно объявить аргумент типа CmArgs, который будет
* заполнен параметрами командной строки при вызове команды.
*/
void cmMethod(CmArgs args) {
log("Команда выполнена")
}
}
ant
В скриптах есть возможность выполнять команды ant.
Для этого используется стандартный groovy
класс
AntBuilder.
Экземпляр этого класса доступен через метод проекта getAnt()
. В этом экземпляре
в качестве базового каталога установлен каталог проекта.
ant.echo(message: "Arguments: ${args}")
Стандартные скрипты
В комплекте Jandcode Core имеется множество стандартных скриптов, которые можно
использовать в проектах. Основные находятся в пакете jandcode.jc.std
.
Многие модули поставляют свои собственные скрипты. Они обычно располагаются
в пакете MODULENAME.jc
.
Заключение
Надеюсь, теперь Вы сможете самостоятельно разобратся в примере, который был показан в начале статьи.