Menyertakan skrip asyik dalam hal asyik lainnya

97

Saya telah membaca cara mengimpor file keren dalam skrip keren lainnya

Saya ingin mendefinisikan fungsi umum dalam satu file keren dan memanggil fungsi tersebut dari file keren lainnya.

Saya mengerti ini akan menggunakan Groovy seperti bahasa scripting yaitu, saya tidak perlu kelas / objek. Saya mencoba sesuatu seperti dsl yang bisa dilakukan dengan menyenangkan. Semua variabel akan ditetapkan dari Java dan saya ingin menjalankan skrip keren di shell.

Apakah ini mungkin? Dapatkah seseorang memberikan beberapa contoh.

Kannan Ekanath
sumber
2
kemungkinan duplikat skrip Muat dari skrip asyik
tim_yates

Jawaban:

107
evaluate(new File("../tools/Tools.groovy"))

Letakkan itu di bagian atas skrip Anda. Itu akan membawa konten file yang keren (ganti saja nama file di antara tanda kutip ganda dengan skrip keren Anda).

Saya melakukan ini dengan kelas yang secara mengejutkan disebut "Tools.groovy".

jmq
sumber
7
Nama file harus sesuai dengan aturan penamaan kelas Java agar ini berfungsi.
willkil
2
Pertanyaan - Bagaimana cara menyampaikan argumen ke skrip yang saya evaluasi menggunakan sintaks ini?
Steve
3
@steve Anda tidak bisa, tetapi Anda dapat menentukan fungsi dalam skrip yang Anda panggil dengan argumen
Nilzor
11
Itu tidak bekerja ... skrip dievaluasi dengan baik tetapi tidak ada deklarasi dalam lingkup pemanggil (def, class, dll.)
LoganMzz
3
Anda harus mengembalikan objek dari panggilan satu, lalu menetapkan hasil evaluasi ke variabel.
LoganMzz
45

Pada Groovy 2.2 dimungkinkan untuk mendeklarasikan kelas skrip dasar dengan @BaseScriptanotasi transformasi AST yang baru .

Contoh:

file MainScript.groovy :

abstract class MainScript extends Script {
    def meaningOfLife = 42
}

file test.groovy :

import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected
emesx
sumber
1
Saya terus mendapatkan "tidak dapat menyelesaikan kelas" saat menggunakan metode ini. Apa yang akan Anda rekomendasikan untuk saya lakukan? Apakah ada cara untuk mengimpor kelas kustom ke skrip keren lainnya?
droidnoob
38

Cara lain untuk melakukannya adalah dengan mendefinisikan fungsi dalam kelas yang menarik dan mengurai serta menambahkan file ke classpath saat runtime:

File sourceFile = new File("path_to_file.groovy");
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile);
GroovyObject myObject = (GroovyObject) groovyClass.newInstance();
grahamparks
sumber
2
Solusi ini bekerja paling baik untuk saya. Ketika saya mencoba menggunakan jawaban yang diterima, saya mendapat pesan kesalahan yang mengatakan bahwa skrip groovy utama saya tidak dapat menyelesaikan kelas yang ditentukan dalam skrip yang dievaluasi. Untuk apa nilainya ...
cBlaine
1
Saya mencoba beberapa pendekatan berbeda yang diposting di SO dan hanya ini yang berhasil. Yang lain melemparkan kesalahan tentang tidak dapat menyelesaikan kelas atau metode. Ini adalah versi yang saya gunakan versi Groovy Versi: 2.2.2 JVM: 1.8.0 Vendor: Oracle Corporation OS: Windows 7.
Kuberchaun
Ini bekerja dengan baik. Pastikan untuk menggunakan GroovyObjectsecara eksplisit, itu bukan placeholder untuk nama kelas Anda sendiri.
memeriksa
1
Masih saya dapatkan: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar
Penolong. Terima kasih kawan!!
Anjana Silva
30

Saya pikir pilihan terbaik adalah mengatur hal-hal utilitas dalam bentuk kelas yang menyenangkan, menambahkannya ke classpath dan membiarkan skrip utama merujuknya melalui kata kunci import.

Contoh:

scripts / DbUtils.groovy

class DbUtils{
    def save(something){...}
}

skrip / script1.groovy:

import DbUtils
def dbUtils = new DbUtils()
def something = 'foobar'
dbUtils.save(something)

menjalankan skrip:

cd scripts
groovy -cp . script1.groovy
bersalju
sumber
Saya ingin tahu bagaimana ini akan bekerja jika Anda memiliki struktur direktori seperti dengan libdan srcdirektori
Gi0rgi0s
9

Cara saya melakukan ini adalah dengan GroovyShell.

GroovyShell shell = new GroovyShell()
def Util = shell.parse(new File('Util.groovy'))
def data = Util.fetchData()
mikedave
sumber
6

Groovy tidak memiliki kata kunci impor seperti bahasa skrip biasa yang akan memasukkan konten file lain secara literal (disinggung di sini: Apakah groovy menyediakan mekanisme penyertaan? ).
Karena sifatnya yang berorientasi objek / kelas, Anda harus "bermain-main" untuk membuat hal-hal seperti ini berhasil. Salah satu kemungkinannya adalah membuat semua fungsi utilitas Anda statis (karena Anda mengatakan mereka tidak menggunakan objek) dan kemudian melakukan impor statis dalam konteks shell yang Anda jalankan. Kemudian Anda dapat memanggil metode ini seperti "fungsi global".
Kemungkinan lain adalah menggunakan objek Binding ( http://groovy.codehaus.org/api/groovy/lang/Binding.html) saat membuat Shell Anda dan mengikat semua fungsi yang Anda inginkan ke metode (sisi negatifnya di sini harus menyebutkan semua metode dalam penjilidan tetapi Anda mungkin dapat menggunakan refleksi). Namun solusi lain adalah menimpa methodMissing(...)objek delegasi yang ditugaskan ke shell Anda yang pada dasarnya memungkinkan Anda melakukan pengiriman dinamis menggunakan peta atau metode apa pun yang Anda inginkan.

Beberapa dari metode ini ditunjukkan di sini: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Beri tahu saya jika Anda ingin melihat contoh teknik tertentu.

omnisis
sumber
7
tautan ini sekarang sudah mati
Nicolas Mommaerts
5

Berikut adalah contoh lengkap memasukkan satu skrip ke dalam skrip lainnya.
Jalankan saja file Testmain.groovy
Penjelasan komentar disertakan karena saya baik seperti itu;]

Testutils.groovy

// This is the 'include file'
// Testmain.groovy will load it as an implicit class
// Each method in here will become a method on the implicit class

def myUtilityMethod(String msg) {
    println "myUtilityMethod running with: ${msg}"
}

Testmain.groovy

// Run this file

// evaluate implicitly creates a class based on the filename specified
evaluate(new File("./Testutils.groovy"))
// Safer to use 'def' here as Groovy seems fussy about whether the filename (and therefore implicit class name) has a capital first letter
def tu = new Testutils()
tu.myUtilityMethod("hello world")
davidfrancis
sumber
0

Untuk pengguna yang terlambat, tampaknya groovy sekarang mendukung :load file-pathperintah yang hanya mengalihkan masukan dari file yang diberikan, jadi sekarang mudah untuk menyertakan skrip perpustakaan.

Ini berfungsi sebagai input ke groovysh & sebagai baris dalam file yang dimuat:
groovy:000> :load file1.groovy

file1.groovy dapat berisi:
:load path/to/another/file invoke_fn_from_file();

Jack Punt
sumber
Bisakah Anda memperluas ini? Dimana ini di dokumen? Dimana saya taruh :load file-path?
Christoffer Hammarström
Yah, ini bekerja sebagai masukan ke groovysh & sebagai baris dalam file yang dimuat: <br/> groovy:000> :load file1.groovy file1.groovy dapat berisi: <br/>:load path/to/another/file
Jack Punt
1
Saya menemukan beban di dokumen . Jika saya mengerti dengan benar, itu hanya bekerja dengan groovysh?
Christoffer Hammarström
Ini tidak akan bekerja dengan jalur yang didefinisikan di dalam variabel, bukan?
pengguna2173353
0

Kombinasi jawaban @grahamparks dan @snowindy dengan beberapa modifikasi adalah yang berhasil untuk skrip Groovy saya yang berjalan di Tomcat:

Utils.groovy

class Utils {
    def doSth() {...}
}

MyScript.groovy:

/* import Utils --> This import does not work. The class is not even defined at this time */
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(new File("full_path_to/Utils.groovy")); // Otherwise it assumes current dir is $CATALINA_HOME
def foo = groovyClass.newInstance(); // 'def' solves compile time errors!!
foo.doSth(); // Actually works!
Sergio Muriel
sumber
Saya mendapatkan: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar
0

Groovy dapat mengimpor kelas groovy lainnya persis seperti Java. Pastikan ekstensi file pustaka adalah .groovy.

    $ cat lib/Lib.groovy
    package lib
    class Lib {
       static saySomething() { println 'something' }
       def sum(a,b) { a+b }
    }

    $ cat app.gvy
    import lib.Lib
    Lib.saySomething();
    println new Lib().sum(37,5)

    $ groovy app
    something
    42
mil zarathustra
sumber
-1

Setelah beberapa penyelidikan saya sampai pada kesimpulan bahwa pendekatan berikut tampaknya yang terbaik.

beberapa / sub-paket / Util.groovy

@GrabResolver(name = 'nexus', root = 'https://local-nexus-server:8443/repository/maven-public', m2Compatible = true)
@Grab('com.google.errorprone:error_prone_annotations:2.1.3')
@Grab('com.google.guava:guava:23.0')
@GrabExclude('com.google.errorprone:error_prone_annotations')

import com.google.common.base.Strings

class Util {
    void msg(int a, String b, Map c) {
        println 'Message printed by msg method inside Util.groovy'
        println "Print 5 asterisks using the Guava dependency ${Strings.repeat("*", 5)}"
        println "Arguments are a=$a, b=$b, c=$c"
    }
}

example.groovy

#!/usr/bin/env groovy
Class clazz = new GroovyClassLoader().parseClass("${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy" as File)
GroovyObject u = clazz.newInstance()
u.msg(1, 'b', [a: 'b', c: 'd'])

Untuk menjalankan example.groovyskrip, tambahkan ke jalur sistem Anda dan ketik dari direktori mana pun:

example.groovy

Naskah mencetak:

Message printed by msg method inside Util.groovy
Print 5 asterisks using the Guava dependency *****
Arguments are a=1, b=b, c=[a:b, c:d]

Contoh di atas telah diuji di lingkungan berikut: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

Contoh tersebut menunjukkan hal berikut:

  • Cara menggunakan Utilkelas di dalam skrip yang menarik.
  • Sebuah Utilkelas memanggil Guavalibrary pihak ketiga dengan memasukkan sebagai Grapeketergantungan ( @Grab('com.google.guava:guava:23.0')).
  • The Utilkelas dapat berada di subdirektori.
  • Meneruskan argumen ke metode di dalam Utilkelas.

Komentar / saran tambahan:

  • Selalu gunakan kelas yang asyik sebagai ganti skrip asyik untuk fungsionalitas yang dapat digunakan kembali dalam skrip asyik Anda. Contoh di atas menggunakan kelas Util yang ditentukan dalam file Util.groovy. Menggunakan skrip keren untuk fungsionalitas yang dapat digunakan kembali bermasalah. Misalnya, jika menggunakan skrip groovy maka kelas Util harus dibuat di bagian bawah skrip dengan new Util(), tetapi yang paling penting itu harus ditempatkan dalam file bernama apa pun kecuali Util.groovy. Lihat Skrip versus kelas untuk detail lebih lanjut tentang perbedaan antara skrip keren dan kelas keren.
  • Dalam contoh di atas saya menggunakan path "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"sebagai ganti "some/subpackage/Util.groovy". Ini akan menjamin bahwa Util.groovyfile akan selalu ditemukan dalam kaitannya dengan lokasi skrip groovy ( example.groovy) dan bukan direktori kerja saat ini. Misalnya, menggunakan "some/subpackage/Util.groovy"akan menghasilkan pencarian di WORK_DIR/some/subpackage/Util.groovy.
  • Ikuti konvensi penamaan kelas Java untuk memberi nama skrip keren Anda. Saya pribadi lebih suka penyimpangan kecil di mana skrip dimulai dengan huruf kecil daripada huruf kapital. Misalnya, myScript.groovyadalah nama skrip, dan MyClass.groovymerupakan nama kelas. Penamaan my-script.groovyakan mengakibatkan error runtime dalam skenario tertentu karena kelas yang dihasilkan tidak akan memiliki nama kelas Java yang valid.
  • Di dunia JVM secara umum, fungsionalitas yang relevan dinamai JSR 223: Scripting untuk Java . Secara khusus, groovy fungsinya dinamai mekanisme integrasi Groovy . Faktanya, pendekatan yang sama dapat digunakan untuk memanggil bahasa JVM apa pun dari dalam Groovy atau Java. Beberapa contoh penting dari bahasa JVM tersebut adalah Groovy, Java, Scala, JRuby, dan JavaScript (Rhino).
Georgios F.
sumber