PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /usr/share/ruby/vendor_ruby/puppet/pops/binder
Viewing File: /usr/share/ruby/vendor_ruby/puppet/pops/binder/injector.rb
# The injector is the "lookup service" class # # Initialization # -------------- # The injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}. The Binder instance contains a resolved set of # `key => "binding information"` that is used to setup the injector. # # Lookup # ------ # It is possible to lookup either the value, or a producer of the value. The {#lookup} method looks up a value, and the # {#lookup_producer} looks up a producer. # Both of these methods can be called with three different signatures; `lookup(key)`, `lookup(type, name)`, and `lookup(name)`, # with the corresponding calls to obtain a producer; `lookup_producer(key)`, `lookup_producer(type, name)`, and `lookup_producer(name)`. # # It is possible to pass a block to {#lookup} and {#lookup_producer}, the block is passed the result of the lookup # and the result of the block is returned as the value of the lookup. This is useful in order to provide a default value. # # @example Lookup with default value # injector.lookup('favourite_food') {|x| x.nil? ? 'bacon' : x } # # Singleton or Not # ---------------- # The lookup of a value is always based on the lookup of a producer. For *singleton producers* this means that the value is # determined by the first value lookup. Subsequent lookups via `lookup` or `lookup_producer` will produce the same instance. # # *Non singleton producers* will produce a new instance on each request for a value. For constant value producers this # means that a new deep-clone is produced for mutable objects (but not for immutable objects as this is not needed). # Custom producers should have non singleton behavior, or if this is not possible ensure that the produced result is # immutable. (The behavior if a custom producer hands out a mutable value and this is mutated is undefined). # # Custom bound producers capable of producing a series of objects when bound as a singleton means that the producer # is a singleton, not the value it produces. If such a producer is bound as non singleton, each `lookup` will get a new # producer (hence, typically, restarting the series). However, the producer returned from `lookup_producer` will not # recreate the producer on each call to `produce`; i.e. each `lookup_producer` returns a producer capable of returning # a series of objects. # # @see Puppet::Pops::Binder::Binder Binder, for details about how to bind keys to producers # @see Puppet::Pops::Binder::BindingsFactory BindingsFactory, for a convenient way to create a Binder and bindings # # Assisted Inject # --------------- # The injector supports lookup of instances of classes *even if the requested class is not explicitly bound*. # This is possible for classes that have a zero argument `initialize` method, or that has a class method called # `inject` that takes two arguments; `injector`, and `scope`. # This is useful in ruby logic as a class can then use the given injector to inject details. # An `inject` class method wins over a zero argument `initialize` in all cases. # # @example Using assisted inject # # Class with assisted inject support # class Duck # attr_reader :name, :year_of_birth # # def self.inject(injector, scope, binding, *args) # # lookup default name and year of birth, and use defaults if not present # name = injector.lookup(scope,'default-duck-name') {|x| x ? x : 'Donald Duck' } # year_of_birth = injector.lookup(scope,'default-duck-year_of_birth') {|x| x ? x : 1934 } # self.new(name, year_of_birth) # end # # def initialize(name, year_of_birth) # @name = name # @year_of_birth = year_of_birth # end # end # # injector.lookup(scope, Duck) # # Produces a Duck named 'Donald Duck' or named after the binding 'default-duck-name' (and with similar treatment of # # year_of_birth). # @see Puppet::Pops::Binder::Producers::AssistedInjectProducer AssistedInjectProducer, for more details on assisted injection # # Access to key factory and type calculator # ----------------------------------------- # It is important to use the same key factory, and type calculator as the binder. It is therefor possible to obtain # these with the methods {#key_factory}, and {#type_calculator}. # # Special support for producers # ----------------------------- # There is one method specially designed for producers. The {#get_contributions} method returns an array of all contributions # to a given *contributions key*. This key is obtained from the {#key_factory} for a given multibinding. The returned set of # contributed bindings is sorted in descending precedence order. Any conflicts, merges, etc. is performed by the multibinding # producer configured for a multibinding. # # @api public # class Puppet::Pops::Binder::Injector Producers = Puppet::Pops::Binder::Producers def self.create_from_model(layered_bindings_model) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings_model)) end def self.create_from_hash(name, key_value_hash) factory = Puppet::Pops::Binder::BindingsFactory named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }} layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model)) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings)) end # Creates an injector with a single bindings layer created with the given name, and the bindings # produced by the given block. The block is evaluated with self bound to a BindingsContainerBuilder. # # @example # Injector.create('mysettings') do # bind('name').to(42) # end # # @api public # def self.create(name, &block) factory = Puppet::Pops::Binder::BindingsFactory layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model)) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings)) end # Creates an overriding injector with a single bindings layer # created with the given name, and the bindings produced by the given block. # The block is evaluated with self bound to a BindingsContainerBuilder. # # @example # an_injector.override('myoverrides') do # bind('name').to(43) # end # # @api public # def override(name, &block) factory = Puppet::Pops::Binder::BindingsFactory layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model)) self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end # Creates an overriding injector with bindings from a bindings model (a LayeredBindings) which # may consists of multiple layers of bindings. # # @api public # def override_with_model(layered_bindings) unless layered_bindings.is_a?(Puppet::Pops::Binder::Bindings::LayeredBindings) raise ArgumentError, "Expected a LayeredBindings model, got '#{bindings_model.class}'" end self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end # Creates an overriding injector with a single bindings layer # created with the given name, and the bindings given in the key_value_hash # @api public # def override_with_hash(name, key_value_hash) factory = Puppet::Pops::Binder::BindingsFactory named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }} layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model)) self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end # An Injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}. # # @param configured_binder [Puppet::Pops::Binder::Binder,nil] The configured binder containing effective bindings. A given value # of nil creates an injector that returns or yields nil on all lookup requests. # @raise ArgumentError if the given binder is not fully configured # # @api public # def initialize(configured_binder, parent_injector = nil) if configured_binder.nil? @impl = Private::NullInjectorImpl.new() else @impl = Private::InjectorImpl.new(configured_binder, parent_injector) end end # The KeyFactory used to produce keys in this injector. # The factory is shared with the Binder to ensure consistent translation to keys. # A compatible type calculator can also be obtained from the key factory. # @return [Puppet::Pops::Binder::KeyFactory] the key factory in use # # @api public # def key_factory() @impl.key_factory end # Returns the TypeCalculator in use for keys. The same calculator (as used for keys) should be used if there is a need # to check type conformance, or infer the type of Ruby objects. # # @return [Puppet::Pops::Types::TypeCalculator] the type calculator that is in use for keys # @api public # def type_calculator() @impl.type_calculator() end # Lookup (a.k.a "inject") of a value given a key. # The lookup may be called with different parameters. This method is a convenience method that # dispatches to one of #lookup_key or #lookup_type depending on the arguments. It also provides # the ability to use an optional block that is called with the looked up value, or scope and value if the # block takes two parameters. This is useful to provide a default value or other transformations, calculations # based on the result of the lookup. # # @overload lookup(scope, key) # (see #lookup_key) # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param key [Object] an opaque object being the full key # # @overload lookup(scope, type, name = '') # (see #lookup_type) # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param type [Puppet::Pops::Types::PAnyType] the type of what to lookup # @param name [String] the name to use, defaults to empty string (for unnamed) # # @overload lookup(scope, name) # Lookup of Data type with given name. # @see #lookup_type # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param name [String] the Data/name to lookup # # @yield [value] passes the looked up value to an optional block and returns what this block returns # @yield [scope, value] passes scope and value to the block and returns what this block returns # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup # @yieldparam value [Object, nil] the looked up value or nil if nothing was found # # @raise [ArgumentError] if the block has an arity that is not 1 or 2 # # @api public # def lookup(scope, *args, &block) @impl.lookup(scope, *args, &block) end # Looks up a (typesafe) value based on a type/name combination. # Creates a key for the type/name combination using a KeyFactory. Specialization of the Data type are transformed # to a Data key, and the result is type checked to conform with the given key. # # @param type [Puppet::Pops::Types::PAnyType] the type to lookup as defined by Puppet::Pops::Types::TypeFactory # @param name [String] the (optional for non `Data` types) name of the entry to lookup. # The name may be an empty String (the default), but not nil. The name is required for lookup for subtypes of # `Data`. # @return [Object, nil] the looked up bound object, or nil if not found (type conformance with given type is guaranteed) # @raise [ArgumentError] if the produced value does not conform with the given type # # @api public # def lookup_type(scope, type, name='') @impl.lookup_type(scope, type, name) end # Looks up the key and returns the entry, or nil if no entry is found. # Produced type is checked for type conformance with its binding, but not with the lookup key. # (This since all subtypes of PDataType are looked up using a key based on PDataType). # Use the Puppet::Pops::Types::TypeCalculator#instance? method to check for conformance of the result # if this is wanted, or use #lookup_type. # # @param key [Object] lookup of key as produced by the key factory # @return [Object, nil] produced value of type that conforms with bound type (type conformance with key not guaranteed). # @raise [ArgumentError] if the produced value does not conform with the bound type # # @api public # def lookup_key(scope, key) @impl.lookup_key(scope, key) end # Lookup (a.k.a "inject") producer of a value given a key. # The producer lookup may be called with different parameters. This method is a convenience method that # dispatches to one of #lookup_producer_key or #lookup_producer_type depending on the arguments. It also provides # the ability to use an optional block that is called with the looked up producer, or scope and producer if the # block takes two parameters. This is useful to provide a default value, call a custom producer method, # or other transformations, calculations based on the result of the lookup. # # @overload lookup_producer(scope, key) # (see #lookup_proudcer_key) # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param key [Object] an opaque object being the full key # # @overload lookup_producer(scope, type, name = '') # (see #lookup_type) # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param type [Puppet::Pops::Types::PAnyType], the type of what to lookup # @param name [String], the name to use, defaults to empty string (for unnamed) # # @overload lookup_producer(scope, name) # Lookup of Data type with given name. # @see #lookup_type # @param scope [Puppet::Parser::Scope] the scope to use for evaluation # @param name [String], the Data/name to lookup # # @return [Puppet::Pops::Binder::Producers::Producer, Object, nil] a producer, or what the optional block returns # # @yield [producer] passes the looked up producer to an optional block and returns what this block returns # @yield [scope, producer] passes scope and producer to the block and returns what this block returns # @yieldparam producer [Puppet::Pops::Binder::Producers::Producer, nil] the looked up producer or nil if nothing was bound # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup # # @raise [ArgumentError] if the block has an arity that is not 1 or 2 # # @api public # def lookup_producer(scope, *args, &block) @impl.lookup_producer(scope, *args, &block) end # Looks up a Producer given an opaque binder key. # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found. # # @api public # def lookup_producer_key(scope, key) @impl.lookup_producer_key(scope, key) end # Looks up a Producer given a type/name key. # @note The result is not type checked (it cannot be until the producer has produced an instance). # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found # # @api public # def lookup_producer_type(scope, type, name='') @impl.lookup_producer_type(scope, type, name) end # Returns the contributions to a multibind given its contribution key (as produced by the KeyFactory). # This method is typically used by multibind value producers, but may be used for introspection of the injector's state. # # @param scope [Puppet::Parser::Scope] the scope to use # @param contributions_key [Object] Opaque key as produced by KeyFactory as the contributions key for a multibinding # @return [Array<Puppet::Pops::Binder::InjectorEntry>] the contributions sorted in deecending order of precedence # # @api public # def get_contributions(scope, contributions_key) @impl.get_contributions(scope, contributions_key) end # Returns an Injector that returns (or yields) nil on all lookups, and produces an empty structure for contributions # This method is intended for testing purposes. # def self.null_injector self.new(nil) end # The implementation of the Injector is private. # @see Puppet::Pops::Binder::Injector The public API this module implements. # @api private # module Private # This is a mocking "Null" implementation of Injector. It never finds anything # @api private class NullInjectorImpl attr_reader :entries attr_reader :key_factory attr_reader :type_calculator def initialize @entries = [] @key_factory = Puppet::Pops::Binder::KeyFactory.new() @type_calculator = @key_factory.type_calculator end def lookup(scope, *args, &block) raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2) # call block with result if given if block case block.arity when 1 block.call(nil) when 2 block.call(scope, nil) else raise ArgumentError, "The block should have arity 1 or 2" end else val end end # @api private def binder nil end # @api private def lookup_key(scope, key) nil end # @api private def lookup_producer(scope, *args, &block) lookup(scope, *args, &block) end # @api private def lookup_producer_key(scope, key) nil end # @api private def lookup_producer_type(scope, type, name='') nil end def get_contributions() [] end end # @api private # class InjectorImpl # Hash of key => InjectorEntry # @api private # attr_reader :entries attr_reader :key_factory attr_reader :type_calculator attr_reader :binder def initialize(configured_binder, parent_injector = nil) @binder = configured_binder @parent = parent_injector # TODO: Different error message raise ArgumentError, "Given Binder is not configured" unless configured_binder #&& configured_binder.configured?() @entries = configured_binder.injector_entries() # It is essential that the injector uses the same key factory as the binder since keys must be # represented the same (but still opaque) way. # @key_factory = configured_binder.key_factory() @type_calculator = key_factory.type_calculator() @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform", 2, 2) @recursion_lock = [ ] end # @api private def lookup(scope, *args, &block) raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2) val = case args[ 0 ] when Puppet::Pops::Types::PAnyType lookup_type(scope, *args) when String raise ArgumentError, "lookup of name should only pass the name" unless args.size == 1 lookup_key(scope, key_factory.data_key(args[ 0 ])) else raise ArgumentError, 'lookup using a key should only pass a single key' unless args.size == 1 lookup_key(scope, args[ 0 ]) end # call block with result if given if block case block.arity when 1 block.call(val) when 2 block.call(scope, val) else raise ArgumentError, "The block should have arity 1 or 2" end else val end end # Produces a key for a type/name combination. # @api private def named_key(type, name) key_factory.named_key(type, name) end # Produces a key for a PDataType/name combination # @api private def data_key(name) key_factory.data_key(name) end # @api private def lookup_type(scope, type, name='') val = lookup_key(scope, named_key(type, name)) return nil if val.nil? unless key_factory.type_calculator.instance?(type, val) raise ArgumentError, "Type error: incompatible type, #{type_error_detail(type, val)}" end val end # @api private def type_error_detail(expected, actual) actual_t = type_calculator.infer(actual) "expected: #{type_calculator.string(expected)}, got: #{type_calculator.string(actual_t)}" end # @api private def lookup_key(scope, key) if @recursion_lock.include?(key) raise ArgumentError, "Lookup loop detected for key: #{key}" end begin @recursion_lock.push(key) case entry = get_entry(key) when NilClass @parent ? @parent.lookup_key(scope, key) : nil when Puppet::Pops::Binder::InjectorEntry val = produce(scope, entry) return nil if val.nil? unless key_factory.type_calculator.instance?(entry.binding.type, val) raise "Type error: incompatible type returned by producer, #{type_error_detail(entry.binding.type, val)}" end val when Producers::AssistedInjectProducer entry.produce(scope) else # internal, direct entries entry end ensure @recursion_lock.pop() end end # Should be used to get entries as it converts missing entries to NotFound entries or AssistedInject entries # # @api private def get_entry(key) case entry = entries[ key ] when NilClass # not found, is this an assisted inject? if clazz = assistable_injected_class(key) entry = Producers::AssistedInjectProducer.new(self, clazz) entries[ key ] = entry else entries[ key ] = NotFound.new() entry = nil end when NotFound entry = nil end entry end # Returns contributions to a multibind in precedence order; highest first. # Returns an Array on the form [ [key, entry], [key, entry]] where the key is intended to be used to lookup the value # (or a producer) for that entry. # @api private def get_contributions(scope, contributions_key) result = {} return [] unless contributions = lookup_key(scope, contributions_key) contributions.each { |k| result[k] = get_entry(k) } result.sort {|a, b| a[0] <=> b[0] } #result.sort_by {|key, entry| entry } end # Produces an injectable class given a key, or nil if key does not represent an injectable class # @api private # def assistable_injected_class(key) kt = key_factory.get_type(key) return nil unless kt.is_a?(Puppet::Pops::Types::PRuntimeType) && kt.runtime == :ruby && !key_factory.is_named?(key) type_calculator.injectable_class(kt) end def lookup_producer(scope, *args, &block) raise ArgumentError, "lookup_producer should be called with two or three arguments, got: #{args.size()+1}" unless args.size <= 2 p = case args[ 0 ] when Puppet::Pops::Types::PAnyType lookup_producer_type(scope, *args) when String raise ArgumentError, "lookup_producer of name should only pass the name" unless args.size == 1 lookup_producer_key(scope, key_factory.data_key(args[ 0 ])) else raise ArgumentError, "lookup_producer using a key should only pass a single key" unless args.size == 1 lookup_producer_key(scope, args[ 0 ]) end # call block with result if given if block case block.arity when 1 block.call(p) when 2 block.call(scope, p) else raise ArgumentError, "The block should have arity 1 or 2" end else p end end # @api private def lookup_producer_key(scope, key) if @recursion_lock.include?(key) raise ArgumentError, "Lookup loop detected for key: #{key}" end begin @recursion_lock.push(key) producer(scope, get_entry(key), :multiple_use) ensure @recursion_lock.pop() end end # @api private def lookup_producer_type(scope, type, name='') lookup_producer_key(scope, named_key(type, name)) end # Returns the producer for the entry # @return [Puppet::Pops::Binder::Producers::Producer] the entry's producer. # # @api private # def producer(scope, entry, use) return nil unless entry # not found return entry.producer(scope) if entry.is_a?(Producers::AssistedInjectProducer) unless entry.cached_producer entry.cached_producer = transform(entry.binding.producer, scope, entry) end unless entry.cached_producer raise ArgumentError, "Injector entry without a producer #{format_binding(entry.binding)}" end entry.cached_producer.producer(scope) end # @api private def transform(producer_descriptor, scope, entry) @@transform_visitor.visit_this_2(self, producer_descriptor, scope, entry) end # Returns the produced instance # @return [Object] the produced instance # @api private # def produce(scope, entry) return nil unless entry # not found producer(scope, entry, :single_use).produce(scope) end # @api private def named_arguments_to_hash(named_args) nb = named_args.nil? ? [] : named_args result = {} nb.each {|arg| result[ :"#{arg.name}" ] = arg.value } result end # @api private def merge_producer_options(binding, options) named_arguments_to_hash(binding.producer_args).merge(options) end # @api private def format_binding(b) Puppet::Pops::Binder::Binder.format_binding(b) end # Handles a missing producer (which is valid for a Multibinding where one is selected automatically) # @api private # def transform_NilClass(descriptor, scope, entry) unless entry.binding.is_a?(Puppet::Pops::Binder::Bindings::Multibinding) raise ArgumentError, "Binding without producer detected, #{format_binding(entry.binding)}" end case entry.binding.type when Puppet::Pops::Types::PArrayType transform(Puppet::Pops::Binder::Bindings::ArrayMultibindProducerDescriptor.new(), scope, entry) when Puppet::Pops::Types::PHashType transform(Puppet::Pops::Binder::Bindings::HashMultibindProducerDescriptor.new(), scope, entry) else raise ArgumentError, "Unsupported multibind type, must be an array or hash type, #{format_binding(entry.binding)}" end end # @api private def transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry) make_producer(Producers::ArrayMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args)) end # @api private def transform_HashMultibindProducerDescriptor(descriptor, scope, entry) make_producer(Producers::HashMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args)) end # @api private def transform_ConstantProducerDescriptor(descriptor, scope, entry) producer_class = singleton?(descriptor) ? Producers::SingletonProducer : Producers::DeepCloningProducer producer_class.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => descriptor.value})) end # @api private def transform_InstanceProducerDescriptor(descriptor, scope, entry) make_producer(Producers::InstantiatingProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:class_name => descriptor.class_name, :init_args => descriptor.arguments})) end # @api private def transform_EvaluatingProducerDescriptor(descriptor, scope, entry) make_producer(Producers::EvaluatingProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:expression => descriptor.expression})) end # @api private def make_producer(clazz, descriptor, scope, entry, options) singleton_wrapped(descriptor, scope, entry, clazz.new(self, entry.binding, scope, options)) end # @api private def singleton_wrapped(descriptor, scope, entry, producer) return producer unless singleton?(descriptor) Producers::SingletonProducer.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => producer.produce(scope)})) end # @api private def transform_ProducerProducerDescriptor(descriptor, scope, entry) p = transform(descriptor.producer, scope, entry) clazz = singleton?(descriptor) ? Producers::SingletonProducerProducer : Producers::ProducerProducer clazz.new(self, entry.binding, scope, merge_producer_options(entry.binding, merge_producer_options(entry.binding, { :producer_producer => p }))) end # @api private def transform_LookupProducerDescriptor(descriptor, scope, entry) make_producer(Producers::LookupProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name})) end # @api private def transform_HashLookupProducerDescriptor(descriptor, scope, entry) make_producer(Producers::LookupKeyProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name, :key => descriptor.key})) end # @api private def transform_NonCachingProducerDescriptor(descriptor, scope, entry) # simply delegates to the wrapped producer transform(descriptor.producer, scope, entry) end # @api private def transform_FirstFoundProducerDescriptor(descriptor, scope, entry) make_producer(Producers::FirstFoundProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:producers => descriptor.producers.collect {|p| transform(p, scope, entry) }})) end # @api private def singleton?(descriptor) ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor) end # Special marker class used in entries # @api private class NotFound end end end end