Başka bir harika yazıya harika bir senaryo eklemek


99

Harika bir dosyayı başka bir harika betiğe nasıl aktaracağımı okudum

Bir groovy dosyasında ortak fonksiyonları tanımlamak ve bu fonksiyonları diğer harika dosyalardan çağırmak istiyorum.

Bunun Groovy'yi bir betik dili gibi kullanacağını anlıyorum, yani sınıflara / nesnelere ihtiyacım yok. Harika bir şekilde yapılabilecek dsl gibi bir şey yapmaya çalışıyorum. Tüm değişkenler Java'dan alınacak ve bir kabukta harika bir komut dosyası çalıştırmak istiyorum.

Bu hiç mümkün mü ? Birisi örnek verebilir mi?


Yanıtlar:


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

Bunu senaryonuzun en üstüne koyun. Bu harika bir dosyanın içeriğini getirecektir (sadece çift tırnak arasındaki dosya adını harika betiğinizle değiştirin).

Bunu şaşırtıcı bir şekilde "Tools.groovy" adlı bir sınıfla yapıyorum.


7
Bunun çalışması için dosya adının Java'nın sınıf adlandırma kurallarına uyması gerekir.
willkil

2
Soru - Bu sözdizimini kullanarak değerlendirdiğim betiğe nasıl bağımsız değişken iletebilirim?
Steve

3
@steve Yapamazsınız, ancak bu komut dosyasında argümanlarla çağırdığınız bir işlevi tanımlayabilirsiniz
Nilzor


3
Birinci çağrıdan bir nesne döndürmeli, ardından değerlendirme sonucunu bir değişkene atamalısınız.
LoganMzz

45

Groovy 2.2'den itibaren, yeni @BaseScriptAST dönüşüm ek açıklamasıyla bir temel komut dosyası sınıfı bildirmek mümkündür .

Misal:

MainScript.groovy dosyası :

abstract class MainScript extends Script {
    def meaningOfLife = 42
}

dosya test.groovy :

import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected

1
Bu yöntemi kullanırken "sınıf çözülemiyor" mesajı almaya devam ediyorum. Ne yapmamı önerirsin? Özel sınıfları başka bir harika betiğe aktarmanın bir yolu var mı?
droidnoob

38

Bunu yapmanın başka bir yolu da harika bir sınıftaki işlevleri tanımlamak ve dosyayı çalışma zamanında ayrıştırıp sınıf yoluna eklemektir:

File sourceFile = new File("path_to_file.groovy");
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile);
GroovyObject myObject = (GroovyObject) groovyClass.newInstance();

3
Bu çözüm aslında benim için en iyisi oldu. Kabul edilen cevabı kullanmayı denediğimde, ana harika betiğimin değerlendirilen betikte tanımlanan sınıfı çözemediğini söyleyen bir hata aldım.
Değeri

1
SO'da yayınlanan birkaç farklı yaklaşımı denedim ve yalnızca bu işe yaradı. Diğerleri, sınıfı veya yöntemleri çözememe konusunda hatalar attı. Bu, Groovy sürümünü kullandığım sürümdür. Sürüm: 2.2.2 JVM: 1.8.0 Satıcı: Oracle Corporation İşletim Sistemi: Windows 7
Kuberchaun

1
Bu harika çalıştı. GroovyObjectAçıkça kullandığınızdan emin olun , bu kendi sınıf adınız için bir yer tutucu değildir.
27'de kontrol

1
Hala anlıyorum: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar

Hayat kurtarıcı. Teşekkür ederim ortak!!
Anjana Silva

30

Bence en iyi seçenek, faydalı şeyleri harika sınıflar şeklinde organize etmek, onları sınıf yoluna eklemek ve ana komut dosyasının import anahtar sözcüğü ile bunlara başvurmasına izin vermek.

Misal:

scripts / DbUtils.groovy

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

scripts / script1.groovy:

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

çalışan komut dosyası:

cd scripts
groovy -cp . script1.groovy

Sana olduğu gibi bir dizin yapısı varsa bunların nasıl olacağı merak libve srcdizinleri
Gi0rgi0s

9

Bunu yapma şeklim ile GroovyShell.

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

7

Groovy, başka bir dosyanın içeriğini birebir içerecek tipik komut dosyası dilleri gibi bir içe aktarma anahtar kelimesine sahip değildir (burada ima edilmektedir: groovy bir içerme mekanizması sağlar mı? ).
Nesne / sınıf odaklı doğası nedeniyle, bunun gibi şeylerin çalışması için "oyun oynamanız" gerekir. Bir olasılık, tüm yardımcı program işlevlerinizi statik hale getirmek (nesneleri kullanmadıklarını söylediğiniz için) ve ardından yürütme kabuğunuz bağlamında statik bir içe aktarma gerçekleştirmektir. Daha sonra bu yöntemleri "genel işlevler" gibi çağırabilirsiniz.
Başka bir olasılık, bir Binding nesnesi kullanmak olabilir ( http://groovy.codehaus.org/api/groovy/lang/Binding.html) Kabuğunuzu oluştururken ve istediğiniz tüm işlevleri yöntemlere bağlarken (buradaki dezavantaj, bağlamadaki tüm yöntemleri numaralandırmak zorunda kalacaktır, ancak belki yansıma kullanabilirsiniz). Yine başka bir çözüm methodMissing(...), kabuğunuza atanan delege nesnesini geçersiz kılmak olabilir , bu da temelde bir harita veya istediğiniz yöntemi kullanarak dinamik gönderim yapmanıza izin verir.

Bu yöntemlerden birkaçı burada gösterilmektedir: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Belirli bir tekniğin bir örneğini görmek isterseniz bana bildirin.


7
bu bağlantı artık öldü
Nicolas Mommaerts

7

Harici komut dosyasını bir Java sınıfı olarak ele almaya ne dersiniz? Bu makaleye dayanarak: https://www.jmdawson.net/blog/2014/08/18/using-functions-from-one-groovy-script-in-another/

getThing.groovy Harici komut dosyası

def getThingList() {
    return ["thing","thin2","thing3"]
}

printThing.groovy Ana komut dosyası

thing = new getThing()  // new the class which represents the external script
println thing.getThingList()

Sonuç

$ groovy printThing.groovy
[thing, thin2, thing3]

Komut dosyanızı kaynak deponun dışında çalıştırıyorsanız işe yaramaz
Eugen

6

İşte bir komut dosyasını diğerinin içine dahil etmenin eksiksiz bir örneği.
Sadece Testmain.groovy dosyasını çalıştırın
Açıklayıcı yorumlar dahil, çünkü böyle iyiyim;]

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")

0

Geç gelenler için, artık groovy'nin :load file-pathverilen dosyadan girişi basitçe yeniden yönlendiren komutu desteklediği görülüyor , bu nedenle artık kütüphane komut dosyalarını dahil etmek önemsiz.

Groovysh'a girdi olarak ve yüklenen bir dosyada bir satır olarak çalışır:
groovy:000> :load file1.groovy

file1.groovy şunları içerebilir:
:load path/to/another/file invoke_fn_from_file();


Bunu biraz daha açabilir misin lütfen? Bu belgelerde nerede? İ Nerede koyarım :load file-path?
Christoffer Hammarström

Evet, groovysh'a girdi olarak ve yüklenen bir dosyada bir satır olarak çalışır: <br/> groovy:000> :load file1.groovy file1.groovy şunları içerebilir: <br/>:load path/to/another/file
Jack Punt

1
Dokümanlarda yük buldum . Doğru anlarsam , sadece groovysh ile mi çalışır?
Christoffer Hammarström

Bu bir değişkenin içinde tanımlanan yolla çalışmaz, değil mi?
user2173353

0

@Grahamparks ve @snowindy yanıtlarının birkaç değişiklikle bir kombinasyonu, Tomcat üzerinde çalışan Groovy komut dosyalarım için işe yarayan şeydi:

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!

I get: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar

0

Groovy, Java'nın yaptığı gibi diğer harika sınıfları içe aktarabilir. Kitaplık dosyasının uzantısının .groovy olduğundan emin olun.

    $ 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

-1

Biraz araştırdıktan sonra, aşağıdaki yaklaşımın en iyisi olduğu sonucuna vardım.

some / subpackage / 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'])

example.groovyKomut dosyasını çalıştırmak için sistem yolunuza ekleyin ve herhangi bir dizinden yazın:

example.groovy

Komut dosyası şunu yazdırır:

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]

Yukarıdaki örnek aşağıdaki ortamda test edildi: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

Örnek şunları göstermektedir:

  • UtilHarika bir betik içinde bir sınıf nasıl kullanılır .
  • Üçüncü taraf kitaplığını bağımlılık ( ) olarak Utilekleyerek çağıran bir sınıf .GuavaGrape@Grab('com.google.guava:guava:23.0')
  • UtilSınıf alt dizinde kalabilir.
  • UtilSınıf içindeki bir yönteme bağımsız değişkenler iletme .

Ek yorumlar / öneriler:

  • Harika komut dosyalarınızda yeniden kullanılabilir işlevsellik için her zaman harika bir komut dosyası yerine harika bir sınıf kullanın. Yukarıdaki örnek, Util.groovy dosyasında tanımlanan Util sınıfını kullanır. Yeniden kullanılabilir işlevsellik için harika komut dosyaları kullanmak sorunludur. Örneğin, harika bir komut dosyası kullanılıyorsa, Util sınıfının komut dosyasının altında somutlaştırılması gerekir new Util(), ancak en önemlisi Util.groovy dışında herhangi bir adda bir dosyaya yerleştirilmesi gerekir. Harika komut dosyaları ve harika sınıflar arasındaki farklar hakkında daha fazla ayrıntı için Komut Dosyalarına karşı sınıflara bakın .
  • Yukarıdaki örnekte "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"yerine yolu kullanıyorum "some/subpackage/Util.groovy". Bu, Util.groovydosyanın her zaman harika betiğin bulunduğu yere ( example.groovy) göre bulunacağını ve mevcut çalışma dizini ile ilişkili olmayacağını garanti eder . Örneğin, kullanmak "some/subpackage/Util.groovy", arama ile sonuçlanır WORK_DIR/some/subpackage/Util.groovy.
  • Harika komut dosyalarınızı adlandırmak için Java sınıfı adlandırma kuralını izleyin. Şahsen, senaryoların büyük harf yerine küçük harfle başladığı küçük bir sapmayı tercih ederim. Örneğin myScript.groovy, bir komut dosyası adıdır ve MyClass.groovybir sınıf adıdır. Adlandırma my-script.groovy, belirli senaryolarda çalışma zamanı hatalarına neden olur çünkü ortaya çıkan sınıf geçerli bir Java sınıf adına sahip olmayacaktır.
  • Genel olarak JVM dünyasında ilgili işlevsellik JSR 223: Java için Komut Dosyası olarak adlandırılır . Groovy'de özellikle işlevsellik Groovy entegrasyon mekanizmaları olarak adlandırılır . Aslında, Groovy veya Java'dan herhangi bir JVM dilini çağırmak için aynı yaklaşım kullanılabilir . Bu tür JVM dillerinin bazı dikkate değer örnekleri Groovy, Java, Scala, JRuby ve JavaScript'tir (Rhino).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.