Groovy ประเมิน Strings โดยใช้ DSL ในขณะที่ปิด Groovy

สิ่งนี้คล้ายกับ Need Groovy syntax help for การสร้าง การปิดจากสตริง แต่ซับซ้อนกว่าเล็กน้อย:

ฉันกำลังทำงานกับ DSL ที่ซับซ้อนซึ่งฉันไม่ได้ควบคุม (โดยเฉพาะ Jenkins Job DSL แต่ฉันใช้ DSL เชิงสมมุติเพื่อความชัดเจน) และฉันได้แยกโค้ดออกเป็นการปิดที่ส่งคืน การปิดทั้งหมดที่ไม่ได้ขึ้นต้นด้วย "my" ในโค้ดนี้เป็น DSL สมมุติ:

//scriptContext is a reference to the original script as this is a util class
static def myMethod(def scriptContext) {
    //everything here comes from some hypothetical DSL
    scriptContext.diningTable() {
        ....
        fruits myCreateFruitsClosure()
        ....
    }
}    
static def myCreateFruitsClosure() {
   return {
       apple('Gala') {
           seed("brown")
           shape {
              funky()
              dimpled()
           }
       }
   }
}

ข้างต้นทำงานได้ดี

ตอนนี้ สมมติว่าฉันต้องการให้ระบุรายละเอียดของ apple แบบไดนามิก และฉันโหลดโค้ด Groovy จากที่ไหนสักแห่ง (เช่น XML)

ตอนนี้ฉันมี:

// I pass in the script context for the binding
static def myCreateFruitsClosure(def scriptContext) {
   return {
       apple('Gala') {
           // This comes from somewhere in real life:
           def code = """seed("blue"); shape { oval() ; cardioid() }"""
           def evalWrapper = new GroovyShell(context.binding).evaluate(' { -> ' + code + '}')                      
           evalWrapper()
       }
   }
}

และฉันได้รับ "No Signature of method: Script1.seed()" แน่นอนว่า Seed() วิธีการนั้นมีอยู่เมื่อไม่ได้ใช้ eval เนื่องจากมันใช้งานได้มาก่อน ดังนั้นบริบท/ขอบเขตของฉันจึงผิด

ฉันพยายามแล้ว:

  • การผสมผสานระหว่าง Eval.me() และ Script.evaluate() ทุกประเภท
  • เพื่อสร้างวิธีการและเรียกใช้ทั้งในและนอกประเมิน ()
  • หากต้องการย้ายเนื้อหาของ "createFruitsClosure()" โดยตรงไปที่ "myMethod()"

ทั้งหมดนี้ทำให้เกิดข้อผิดพลาดที่แตกต่างกันเล็กน้อย วิธีที่ถูกต้องคืออะไร?


person Akom    schedule 23.01.2017    source แหล่งที่มา


คำตอบ (1)


ท้ายที่สุด ฉันทำสิ่งนี้สำเร็จ โดย:

  1. เปลี่ยนไปใช้บล็อกโค้ดแบบเปิดแทนการปิด
  2. ใช้การอ้างอิงที่ชัดเจนถึง "เจ้าของ" จากโค้ดไดนามิก และทำให้พร้อมใช้งานผ่านการผูก ในตัวอย่างนี้ "self" ซึ่งเป็นเจ้าของ คือ apple closure

นี่คือผลลัพธ์:

static def myCreateFruitsClosure() {
    return {
        apple {
            def code = """
                L:{
                   self.seed("blue")
                   self.shape {
                       oval()
                       cardioid()
                   }
                }"""  
            // sometimes "self: delegate" is appropriate instead of this:
            new GroovyShell(new Binding([self: owner])).evaluate(code)
        }
    }
}

ฉันเดาว่ามันง่ายกว่าที่ฉันพยายามทำ สังเกต "L:" เพื่อบังคับประเมิน () เพื่อถือว่าโค้ดเป็นบล็อกโค้ดแบบเปิดและไม่ใช่การปิด

หากใครมีวิธีที่ดีกว่านี้แจ้งให้เราทราบ แต่มันก็ใช้ได้ดีเพียงพอ

person Akom    schedule 24.01.2017
comment
พุทโธ่. ฉันใช้เวลาหลายชั่วโมงในการพยายามคิดสิ่งนี้และคิดว่าบางทีฉันอาจจะบ้าไปแล้ว ขอบคุณสำหรับวิธีแก้ปัญหา - มันช่วยได้จริงๆ! - person Kat; 02.05.2018