erubis 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468
  1. #!/usr/bin/env ruby
  2. ###
  3. ### $Release: 2.7.0 $
  4. ### copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  5. ###
  6. #--begin of require 'erubis/main'
  7. ###
  8. ### $Release: 2.7.0 $
  9. ### copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  10. ###
  11. require 'yaml'
  12. #--begin of require 'erubis'
  13. ##
  14. ## $Release: 2.7.0 $
  15. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  16. ##
  17. ##
  18. ## an implementation of eRuby
  19. ##
  20. ## ex.
  21. ## input = <<'END'
  22. ## <ul>
  23. ## <% for item in @list %>
  24. ## <li><%= item %>
  25. ## <%== item %></li>
  26. ## <% end %>
  27. ## </ul>
  28. ## END
  29. ## list = ['<aaa>', 'b&b', '"ccc"']
  30. ## eruby = Erubis::Eruby.new(input)
  31. ## puts "--- code ---"
  32. ## puts eruby.src
  33. ## puts "--- result ---"
  34. ## context = Erubis::Context.new() # or new(:list=>list)
  35. ## context[:list] = list
  36. ## puts eruby.evaluate(context)
  37. ##
  38. ## result:
  39. ## --- source ---
  40. ## _buf = ''; _buf << '<ul>
  41. ## '; for item in @list
  42. ## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
  43. ## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
  44. ## '; end
  45. ## _buf << '</ul>
  46. ## ';
  47. ## _buf.to_s
  48. ## --- result ---
  49. ## <ul>
  50. ## <li><aaa>
  51. ## &lt;aaa&gt;</li>
  52. ## <li>b&b
  53. ## b&amp;b</li>
  54. ## <li>"ccc"
  55. ## &quot;ccc&quot;</li>
  56. ## </ul>
  57. ##
  58. module Erubis
  59. VERSION = ('$Release: 2.7.0 $' =~ /([.\d]+)/) && $1
  60. end
  61. #--begin of require 'erubis/engine'
  62. ##
  63. ## $Release: 2.7.0 $
  64. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  65. ##
  66. #--begin of require 'erubis/generator'
  67. ##
  68. ## $Release: 2.7.0 $
  69. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  70. ##
  71. #--begin of require 'erubis/util'
  72. ##
  73. ## $Release: 2.7.0 $
  74. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  75. ##
  76. module Kernel
  77. ##
  78. ## raise NotImplementedError
  79. ##
  80. def not_implemented #:doc:
  81. backtrace = caller()
  82. method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
  83. mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
  84. #mesg = "#{self.class.name}##{method_name}() is not implemented."
  85. err = NotImplementedError.new mesg
  86. err.set_backtrace backtrace
  87. raise err
  88. end
  89. private :not_implemented
  90. end
  91. #--end of require 'erubis/util'
  92. module Erubis
  93. ##
  94. ## code generator, called by Converter module
  95. ##
  96. module Generator
  97. def self.supported_properties() # :nodoc:
  98. return [
  99. [:escapefunc, nil, "escape function name"],
  100. ]
  101. end
  102. attr_accessor :escapefunc
  103. def init_generator(properties={})
  104. @escapefunc = properties[:escapefunc]
  105. end
  106. ## (abstract) escape text string
  107. ##
  108. ## ex.
  109. ## def escape_text(text)
  110. ## return text.dump
  111. ## # or return "'" + text.gsub(/['\\]/, '\\\\\&') + "'"
  112. ## end
  113. def escape_text(text)
  114. not_implemented
  115. end
  116. ## return escaped expression code (ex. 'h(...)' or 'htmlspecialchars(...)')
  117. def escaped_expr(code)
  118. code.strip!
  119. return "#{@escapefunc}(#{code})"
  120. end
  121. ## (abstract) add @preamble to src
  122. def add_preamble(src)
  123. not_implemented
  124. end
  125. ## (abstract) add text string to src
  126. def add_text(src, text)
  127. not_implemented
  128. end
  129. ## (abstract) add statement code to src
  130. def add_stmt(src, code)
  131. not_implemented
  132. end
  133. ## (abstract) add expression literal code to src. this is called by add_expr().
  134. def add_expr_literal(src, code)
  135. not_implemented
  136. end
  137. ## (abstract) add escaped expression code to src. this is called by add_expr().
  138. def add_expr_escaped(src, code)
  139. not_implemented
  140. end
  141. ## (abstract) add expression code to src for debug. this is called by add_expr().
  142. def add_expr_debug(src, code)
  143. not_implemented
  144. end
  145. ## (abstract) add @postamble to src
  146. def add_postamble(src)
  147. not_implemented
  148. end
  149. end
  150. end
  151. #--end of require 'erubis/generator'
  152. #--begin of require 'erubis/converter'
  153. ##
  154. ## $Release: 2.7.0 $
  155. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  156. ##
  157. #--already included require 'erubis/util'
  158. module Erubis
  159. ##
  160. ## convert
  161. ##
  162. module Converter
  163. attr_accessor :preamble, :postamble, :escape
  164. def self.supported_properties # :nodoc:
  165. return [
  166. [:preamble, nil, "preamble (no preamble when false)"],
  167. [:postamble, nil, "postamble (no postamble when false)"],
  168. [:escape, nil, "escape expression or not in default"],
  169. ]
  170. end
  171. def init_converter(properties={})
  172. @preamble = properties[:preamble]
  173. @postamble = properties[:postamble]
  174. @escape = properties[:escape]
  175. end
  176. ## convert input string into target language
  177. def convert(input)
  178. codebuf = "" # or []
  179. @preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
  180. convert_input(codebuf, input)
  181. @postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
  182. @_proc = nil # clear cached proc object
  183. return codebuf # or codebuf.join()
  184. end
  185. protected
  186. ##
  187. ## detect spaces at beginning of line
  188. ##
  189. def detect_spaces_at_bol(text, is_bol)
  190. lspace = nil
  191. if text.empty?
  192. lspace = "" if is_bol
  193. elsif text[-1] == ?\n
  194. lspace = ""
  195. else
  196. rindex = text.rindex(?\n)
  197. if rindex
  198. s = text[rindex+1..-1]
  199. if s =~ /\A[ \t]*\z/
  200. lspace = s
  201. #text = text[0..rindex]
  202. text[rindex+1..-1] = ''
  203. end
  204. else
  205. if is_bol && text =~ /\A[ \t]*\z/
  206. #lspace = text
  207. #text = nil
  208. lspace = text.dup
  209. text[0..-1] = ''
  210. end
  211. end
  212. end
  213. return lspace
  214. end
  215. ##
  216. ## (abstract) convert input to code
  217. ##
  218. def convert_input(codebuf, input)
  219. not_implemented
  220. end
  221. end
  222. module Basic
  223. end
  224. ##
  225. ## basic converter which supports '<% ... %>' notation.
  226. ##
  227. module Basic::Converter
  228. include Erubis::Converter
  229. def self.supported_properties # :nodoc:
  230. return [
  231. [:pattern, '<% %>', "embed pattern"],
  232. [:trim, true, "trim spaces around <% ... %>"],
  233. ]
  234. end
  235. attr_accessor :pattern, :trim
  236. def init_converter(properties={})
  237. super(properties)
  238. @pattern = properties[:pattern]
  239. @trim = properties[:trim] != false
  240. end
  241. protected
  242. ## return regexp of pattern to parse eRuby script
  243. def pattern_regexp(pattern)
  244. @prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
  245. #return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
  246. #return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
  247. return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
  248. end
  249. module_function :pattern_regexp
  250. #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  251. #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  252. #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  253. DEFAULT_REGEXP = pattern_regexp('<% %>')
  254. public
  255. def convert_input(src, input)
  256. pat = @pattern
  257. regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
  258. pos = 0
  259. is_bol = true # is beginning of line
  260. input.scan(regexp) do |indicator, code, tailch, rspace|
  261. match = Regexp.last_match()
  262. len = match.begin(0) - pos
  263. text = input[pos, len]
  264. pos = match.end(0)
  265. ch = indicator ? indicator[0] : nil
  266. lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
  267. is_bol = rspace ? true : false
  268. add_text(src, text) if text && !text.empty?
  269. ## * when '<%= %>', do nothing
  270. ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
  271. if ch == ?= # <%= %>
  272. rspace = nil if tailch && !tailch.empty?
  273. add_text(src, lspace) if lspace
  274. add_expr(src, code, indicator)
  275. add_text(src, rspace) if rspace
  276. elsif ch == ?\# # <%# %>
  277. n = code.count("\n") + (rspace ? 1 : 0)
  278. if @trim && lspace && rspace
  279. add_stmt(src, "\n" * n)
  280. else
  281. add_text(src, lspace) if lspace
  282. add_stmt(src, "\n" * n)
  283. add_text(src, rspace) if rspace
  284. end
  285. elsif ch == ?% # <%% %>
  286. s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
  287. add_text(src, s)
  288. else # <% %>
  289. if @trim && lspace && rspace
  290. add_stmt(src, "#{lspace}#{code}#{rspace}")
  291. else
  292. add_text(src, lspace) if lspace
  293. add_stmt(src, code)
  294. add_text(src, rspace) if rspace
  295. end
  296. end
  297. end
  298. #rest = $' || input # ruby1.8
  299. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  300. add_text(src, rest)
  301. end
  302. ## add expression code to src
  303. def add_expr(src, code, indicator)
  304. case indicator
  305. when '='
  306. @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
  307. when '=='
  308. @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
  309. when '==='
  310. add_expr_debug(src, code)
  311. end
  312. end
  313. end
  314. module PI
  315. end
  316. ##
  317. ## Processing Instructions (PI) converter for XML.
  318. ## this class converts '<?rb ... ?>' and '${...}' notation.
  319. ##
  320. module PI::Converter
  321. include Erubis::Converter
  322. def self.desc # :nodoc:
  323. "use processing instructions (PI) instead of '<% %>'"
  324. end
  325. def self.supported_properties # :nodoc:
  326. return [
  327. [:trim, true, "trim spaces around <% ... %>"],
  328. [:pi, 'rb', "PI (Processing Instrunctions) name"],
  329. [:embchar, '@', "char for embedded expression pattern('@{...}@')"],
  330. [:pattern, '<% %>', "embed pattern"],
  331. ]
  332. end
  333. attr_accessor :pi, :prefix
  334. def init_converter(properties={})
  335. super(properties)
  336. @trim = properties.fetch(:trim, true)
  337. @pi = properties[:pi] if properties[:pi]
  338. @embchar = properties[:embchar] || '@'
  339. @pattern = properties[:pattern]
  340. @pattern = '<% %>' if @pattern.nil? #|| @pattern == true
  341. end
  342. def convert(input)
  343. code = super(input)
  344. return @header || @footer ? "#{@header}#{code}#{@footer}" : code
  345. end
  346. protected
  347. def convert_input(codebuf, input)
  348. unless @regexp
  349. @pi ||= 'e'
  350. ch = Regexp.escape(@embchar)
  351. if @pattern
  352. left, right = @pattern.split(' ')
  353. @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
  354. else
  355. @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
  356. end
  357. end
  358. #
  359. is_bol = true
  360. pos = 0
  361. input.scan(@regexp) do |pi_arg, stmt, rspace,
  362. indicator1, expr1, indicator2, expr2|
  363. match = Regexp.last_match
  364. len = match.begin(0) - pos
  365. text = input[pos, len]
  366. pos = match.end(0)
  367. lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
  368. is_bol = stmt && rspace ? true : false
  369. add_text(codebuf, text) # unless text.empty?
  370. #
  371. if stmt
  372. if @trim && lspace && rspace
  373. add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
  374. else
  375. add_text(codebuf, lspace) if lspace
  376. add_pi_stmt(codebuf, stmt, pi_arg)
  377. add_text(codebuf, rspace) if rspace
  378. end
  379. else
  380. add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
  381. end
  382. end
  383. #rest = $' || input # ruby1.8
  384. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  385. add_text(codebuf, rest)
  386. end
  387. #--
  388. #def convert_input(codebuf, input)
  389. # parse_stmts(codebuf, input)
  390. # #parse_stmts2(codebuf, input)
  391. #end
  392. #
  393. #def parse_stmts(codebuf, input)
  394. # #regexp = pattern_regexp(@pattern)
  395. # @pi ||= 'e'
  396. # @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
  397. # is_bol = true
  398. # pos = 0
  399. # input.scan(@stmt_pattern) do |pi_arg, code, rspace|
  400. # match = Regexp.last_match
  401. # len = match.begin(0) - pos
  402. # text = input[pos, len]
  403. # pos = match.end(0)
  404. # lspace = detect_spaces_at_bol(text, is_bol)
  405. # is_bol = rspace ? true : false
  406. # parse_exprs(codebuf, text) # unless text.empty?
  407. # if @trim && lspace && rspace
  408. # add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
  409. # else
  410. # add_text(codebuf, lspace)
  411. # add_pi_stmt(codebuf, code, pi_arg)
  412. # add_text(codebuf, rspace)
  413. # end
  414. # end
  415. # rest = $' || input
  416. # parse_exprs(codebuf, rest)
  417. #end
  418. #
  419. #def parse_exprs(codebuf, input)
  420. # unless @expr_pattern
  421. # ch = Regexp.escape(@embchar)
  422. # if @pattern
  423. # left, right = @pattern.split(' ')
  424. # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
  425. # else
  426. # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
  427. # end
  428. # end
  429. # pos = 0
  430. # input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
  431. # indicator = indicator1 || indicator2
  432. # code = code1 || code2
  433. # match = Regexp.last_match
  434. # len = match.begin(0) - pos
  435. # text = input[pos, len]
  436. # pos = match.end(0)
  437. # add_text(codebuf, text) # unless text.empty?
  438. # add_pi_expr(codebuf, code, indicator)
  439. # end
  440. # rest = $' || input
  441. # add_text(codebuf, rest)
  442. #end
  443. #++
  444. def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
  445. case pi_arg
  446. when nil ; add_stmt(codebuf, code)
  447. when 'header' ; @header = code
  448. when 'footer' ; @footer = code
  449. when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
  450. when 'value' ; add_expr_literal(codebuf, code)
  451. else ; add_stmt(codebuf, code)
  452. end
  453. end
  454. def add_pi_expr(codebuf, code, indicator) # :nodoc:
  455. case indicator
  456. when nil, '', '==' # @{...}@ or <%== ... %>
  457. @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
  458. when '!', '=' # @!{...}@ or <%= ... %>
  459. @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
  460. when '!!', '===' # @!!{...}@ or <%=== ... %>
  461. add_expr_debug(codebuf, code)
  462. else
  463. # ignore
  464. end
  465. end
  466. end
  467. end
  468. #--end of require 'erubis/converter'
  469. #--begin of require 'erubis/evaluator'
  470. ##
  471. ## $Release: 2.7.0 $
  472. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  473. ##
  474. #--begin of require 'erubis/error'
  475. ##
  476. ## $Release: 2.7.0 $
  477. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  478. ##
  479. module Erubis
  480. ##
  481. ## base error class
  482. ##
  483. class ErubisError < StandardError
  484. end
  485. ##
  486. ## raised when method or function is not supported
  487. ##
  488. class NotSupportedError < ErubisError
  489. end
  490. end
  491. #--end of require 'erubis/error'
  492. #--begin of require 'erubis/context'
  493. ##
  494. ## $Release: 2.7.0 $
  495. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  496. ##
  497. module Erubis
  498. ##
  499. ## context object for Engine#evaluate
  500. ##
  501. ## ex.
  502. ## template = <<'END'
  503. ## Hello <%= @user %>!
  504. ## <% for item in @list %>
  505. ## - <%= item %>
  506. ## <% end %>
  507. ## END
  508. ##
  509. ## context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
  510. ## # or
  511. ## # context = Erubis::Context.new
  512. ## # context[:user] = 'World'
  513. ## # context[:list] = ['a', 'b', 'c']
  514. ##
  515. ## eruby = Erubis::Eruby.new(template)
  516. ## print eruby.evaluate(context)
  517. ##
  518. class Context
  519. include Enumerable
  520. def initialize(hash=nil)
  521. hash.each do |name, value|
  522. self[name] = value
  523. end if hash
  524. end
  525. def [](key)
  526. return instance_variable_get("@#{key}")
  527. end
  528. def []=(key, value)
  529. return instance_variable_set("@#{key}", value)
  530. end
  531. def keys
  532. return instance_variables.collect { |name| name[1..-1] }
  533. end
  534. def each
  535. instance_variables.each do |name|
  536. key = name[1..-1]
  537. value = instance_variable_get(name)
  538. yield(key, value)
  539. end
  540. end
  541. def to_hash
  542. hash = {}
  543. self.keys.each { |key| hash[key] = self[key] }
  544. return hash
  545. end
  546. def update(context_or_hash)
  547. arg = context_or_hash
  548. if arg.is_a?(Hash)
  549. arg.each do |key, val|
  550. self[key] = val
  551. end
  552. else
  553. arg.instance_variables.each do |varname|
  554. key = varname[1..-1]
  555. val = arg.instance_variable_get(varname)
  556. self[key] = val
  557. end
  558. end
  559. end
  560. end
  561. end
  562. #--end of require 'erubis/context'
  563. module Erubis
  564. EMPTY_BINDING = binding()
  565. ##
  566. ## evaluate code
  567. ##
  568. module Evaluator
  569. def self.supported_properties # :nodoc:
  570. return []
  571. end
  572. attr_accessor :src, :filename
  573. def init_evaluator(properties)
  574. @filename = properties[:filename]
  575. end
  576. def result(*args)
  577. raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
  578. end
  579. def evaluate(*args)
  580. raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
  581. end
  582. end
  583. ##
  584. ## evaluator for Ruby
  585. ##
  586. module RubyEvaluator
  587. include Evaluator
  588. def self.supported_properties # :nodoc:
  589. list = Evaluator.supported_properties
  590. return list
  591. end
  592. ## eval(@src) with binding object
  593. def result(_binding_or_hash=TOPLEVEL_BINDING)
  594. _arg = _binding_or_hash
  595. if _arg.is_a?(Hash)
  596. _b = binding()
  597. eval _arg.collect{|k,v| "#{k} = _arg[#{k.inspect}]; "}.join, _b
  598. elsif _arg.is_a?(Binding)
  599. _b = _arg
  600. elsif _arg.nil?
  601. _b = binding()
  602. else
  603. raise ArgumentError.new("#{self.class.name}#result(): argument should be Binding or Hash but passed #{_arg.class.name} object.")
  604. end
  605. return eval(@src, _b, (@filename || '(erubis'))
  606. end
  607. ## invoke context.instance_eval(@src)
  608. def evaluate(_context=Context.new)
  609. _context = Context.new(_context) if _context.is_a?(Hash)
  610. #return _context.instance_eval(@src, @filename || '(erubis)')
  611. #@_proc ||= eval("proc { #{@src} }", Erubis::EMPTY_BINDING, @filename || '(erubis)')
  612. @_proc ||= eval("proc { #{@src} }", binding(), @filename || '(erubis)')
  613. return _context.instance_eval(&@_proc)
  614. end
  615. ## if object is an Class or Module then define instance method to it,
  616. ## else define singleton method to it.
  617. def def_method(object, method_name, filename=nil)
  618. m = object.is_a?(Module) ? :module_eval : :instance_eval
  619. object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
  620. end
  621. end
  622. end
  623. #--end of require 'erubis/evaluator'
  624. #--already included require 'erubis/context'
  625. module Erubis
  626. ##
  627. ## (abstract) abstract engine class.
  628. ## subclass must include evaluator and converter module.
  629. ##
  630. class Engine
  631. #include Evaluator
  632. #include Converter
  633. #include Generator
  634. def initialize(input=nil, properties={})
  635. #@input = input
  636. init_generator(properties)
  637. init_converter(properties)
  638. init_evaluator(properties)
  639. @src = convert(input) if input
  640. end
  641. ##
  642. ## convert input string and set it to @src
  643. ##
  644. def convert!(input)
  645. @src = convert(input)
  646. end
  647. ##
  648. ## load file, write cache file, and return engine object.
  649. ## this method create code cache file automatically.
  650. ## cachefile name can be specified with properties[:cachename],
  651. ## or filname + 'cache' is used as default.
  652. ##
  653. def self.load_file(filename, properties={})
  654. cachename = properties[:cachename] || (filename + '.cache')
  655. properties[:filename] = filename
  656. timestamp = File.mtime(filename)
  657. if test(?f, cachename) && timestamp == File.mtime(cachename)
  658. engine = self.new(nil, properties)
  659. engine.src = File.read(cachename)
  660. else
  661. input = File.open(filename, 'rb') {|f| f.read }
  662. engine = self.new(input, properties)
  663. tmpname = cachename + rand().to_s[1,8]
  664. File.open(tmpname, 'wb') {|f| f.write(engine.src) }
  665. File.rename(tmpname, cachename)
  666. File.utime(timestamp, timestamp, cachename)
  667. end
  668. engine.src.untaint # ok?
  669. return engine
  670. end
  671. ##
  672. ## helper method to convert and evaluate input text with context object.
  673. ## context may be Binding, Hash, or Object.
  674. ##
  675. def process(input, context=nil, filename=nil)
  676. code = convert(input)
  677. filename ||= '(erubis)'
  678. if context.is_a?(Binding)
  679. return eval(code, context, filename)
  680. else
  681. context = Context.new(context) if context.is_a?(Hash)
  682. return context.instance_eval(code, filename)
  683. end
  684. end
  685. ##
  686. ## helper method evaluate Proc object with contect object.
  687. ## context may be Binding, Hash, or Object.
  688. ##
  689. def process_proc(proc_obj, context=nil, filename=nil)
  690. if context.is_a?(Binding)
  691. filename ||= '(erubis)'
  692. return eval(proc_obj, context, filename)
  693. else
  694. context = Context.new(context) if context.is_a?(Hash)
  695. return context.instance_eval(&proc_obj)
  696. end
  697. end
  698. end # end of class Engine
  699. ##
  700. ## (abstract) base engine class for Eruby, Eperl, Ejava, and so on.
  701. ## subclass must include generator.
  702. ##
  703. class Basic::Engine < Engine
  704. include Evaluator
  705. include Basic::Converter
  706. include Generator
  707. end
  708. class PI::Engine < Engine
  709. include Evaluator
  710. include PI::Converter
  711. include Generator
  712. end
  713. end
  714. #--end of require 'erubis/engine'
  715. #require 'erubis/generator'
  716. #require 'erubis/converter'
  717. #require 'erubis/evaluator'
  718. #require 'erubis/error'
  719. #require 'erubis/context'
  720. #requier 'erubis/util'
  721. #--begin of require 'erubis/helper'
  722. ##
  723. ## $Release: 2.7.0 $
  724. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  725. ##
  726. module Erubis
  727. ##
  728. ## helper for xml
  729. ##
  730. module XmlHelper
  731. module_function
  732. ESCAPE_TABLE = {
  733. '&' => '&amp;',
  734. '<' => '&lt;',
  735. '>' => '&gt;',
  736. '"' => '&quot;',
  737. "'" => '&#039;',
  738. }
  739. def escape_xml(value)
  740. value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
  741. #value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
  742. end
  743. def escape_xml2(value)
  744. return value.to_s.gsub(/\&/,'&amp;').gsub(/</,'&lt;').gsub(/>/,'&gt;').gsub(/"/,'&quot;')
  745. end
  746. alias h escape_xml
  747. alias html_escape escape_xml
  748. def url_encode(str)
  749. return str.gsub(/[^-_.a-zA-Z0-9]+/) { |s|
  750. s.unpack('C*').collect { |i| "%%%02X" % i }.join
  751. }
  752. end
  753. alias u url_encode
  754. end
  755. end
  756. #--end of require 'erubis/helper'
  757. #--begin of require 'erubis/enhancer'
  758. ##
  759. ## $Release: 2.7.0 $
  760. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  761. ##
  762. module Erubis
  763. ##
  764. ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
  765. ##
  766. ## ex.
  767. ## class XmlEruby < Eruby
  768. ## include EscapeEnhancer
  769. ## end
  770. ##
  771. ## this is language-indenedent.
  772. ##
  773. module EscapeEnhancer
  774. def self.desc # :nodoc:
  775. "switch '<%= %>' to escaped and '<%== %>' to unescaped"
  776. end
  777. #--
  778. #def self.included(klass)
  779. # klass.class_eval <<-END
  780. # alias _add_expr_literal add_expr_literal
  781. # alias _add_expr_escaped add_expr_escaped
  782. # alias add_expr_literal _add_expr_escaped
  783. # alias add_expr_escaped _add_expr_literal
  784. # END
  785. #end
  786. #++
  787. def add_expr(src, code, indicator)
  788. case indicator
  789. when '='
  790. @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
  791. when '=='
  792. @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
  793. when '==='
  794. add_expr_debug(src, code)
  795. end
  796. end
  797. end
  798. #--
  799. ## (obsolete)
  800. #module FastEnhancer
  801. #end
  802. #++
  803. ##
  804. ## use $stdout instead of string
  805. ##
  806. ## this is only for Eruby.
  807. ##
  808. module StdoutEnhancer
  809. def self.desc # :nodoc:
  810. "use $stdout instead of array buffer or string buffer"
  811. end
  812. def add_preamble(src)
  813. src << "#{@bufvar} = $stdout;"
  814. end
  815. def add_postamble(src)
  816. src << "\n''\n"
  817. end
  818. end
  819. ##
  820. ## use print statement instead of '_buf << ...'
  821. ##
  822. ## this is only for Eruby.
  823. ##
  824. module PrintOutEnhancer
  825. def self.desc # :nodoc:
  826. "use print statement instead of '_buf << ...'"
  827. end
  828. def add_preamble(src)
  829. end
  830. def add_text(src, text)
  831. src << " print '#{escape_text(text)}';" unless text.empty?
  832. end
  833. def add_expr_literal(src, code)
  834. src << " print((#{code}).to_s);"
  835. end
  836. def add_expr_escaped(src, code)
  837. src << " print #{escaped_expr(code)};"
  838. end
  839. def add_postamble(src)
  840. src << "\n" unless src[-1] == ?\n
  841. end
  842. end
  843. ##
  844. ## enable print function
  845. ##
  846. ## Notice: use Eruby#evaluate() and don't use Eruby#result()
  847. ## to be enable print function.
  848. ##
  849. ## this is only for Eruby.
  850. ##
  851. module PrintEnabledEnhancer
  852. def self.desc # :nodoc:
  853. "enable to use print function in '<% %>'"
  854. end
  855. def add_preamble(src)
  856. src << "@_buf = "
  857. super
  858. end
  859. def print(*args)
  860. args.each do |arg|
  861. @_buf << arg.to_s
  862. end
  863. end
  864. def evaluate(context=nil)
  865. _src = @src
  866. if context.is_a?(Hash)
  867. context.each do |key, val| instance_variable_set("@#{key}", val) end
  868. elsif context
  869. context.instance_variables.each do |name|
  870. instance_variable_set(name, context.instance_variable_get(name))
  871. end
  872. end
  873. return instance_eval(_src, (@filename || '(erubis)'))
  874. end
  875. end
  876. ##
  877. ## return array instead of string
  878. ##
  879. ## this is only for Eruby.
  880. ##
  881. module ArrayEnhancer
  882. def self.desc # :nodoc:
  883. "return array instead of string"
  884. end
  885. def add_preamble(src)
  886. src << "#{@bufvar} = [];"
  887. end
  888. def add_postamble(src)
  889. src << "\n" unless src[-1] == ?\n
  890. src << "#{@bufvar}\n"
  891. end
  892. end
  893. ##
  894. ## use an Array object as buffer (included in Eruby by default)
  895. ##
  896. ## this is only for Eruby.
  897. ##
  898. module ArrayBufferEnhancer
  899. def self.desc # :nodoc:
  900. "use an Array object for buffering (included in Eruby class)"
  901. end
  902. def add_preamble(src)
  903. src << "_buf = [];"
  904. end
  905. def add_postamble(src)
  906. src << "\n" unless src[-1] == ?\n
  907. src << "_buf.join\n"
  908. end
  909. end
  910. ##
  911. ## use String class for buffering
  912. ##
  913. ## this is only for Eruby.
  914. ##
  915. module StringBufferEnhancer
  916. def self.desc # :nodoc:
  917. "use a String object for buffering"
  918. end
  919. def add_preamble(src)
  920. src << "#{@bufvar} = '';"
  921. end
  922. def add_postamble(src)
  923. src << "\n" unless src[-1] == ?\n
  924. src << "#{@bufvar}.to_s\n"
  925. end
  926. end
  927. ##
  928. ## use StringIO class for buffering
  929. ##
  930. ## this is only for Eruby.
  931. ##
  932. module StringIOEnhancer # :nodoc:
  933. def self.desc # :nodoc:
  934. "use a StringIO object for buffering"
  935. end
  936. def add_preamble(src)
  937. src << "#{@bufvar} = StringIO.new;"
  938. end
  939. def add_postamble(src)
  940. src << "\n" unless src[-1] == ?\n
  941. src << "#{@bufvar}.string\n"
  942. end
  943. end
  944. ##
  945. ## set buffer variable name to '_erbout' as well as '_buf'
  946. ##
  947. ## this is only for Eruby.
  948. ##
  949. module ErboutEnhancer
  950. def self.desc # :nodoc:
  951. "set '_erbout = _buf = \"\";' to be compatible with ERB."
  952. end
  953. def add_preamble(src)
  954. src << "_erbout = #{@bufvar} = '';"
  955. end
  956. def add_postamble(src)
  957. src << "\n" unless src[-1] == ?\n
  958. src << "#{@bufvar}.to_s\n"
  959. end
  960. end
  961. ##
  962. ## remove text and leave code, especially useful when debugging.
  963. ##
  964. ## ex.
  965. ## $ erubis -s -E NoText file.eruby | more
  966. ##
  967. ## this is language independent.
  968. ##
  969. module NoTextEnhancer
  970. def self.desc # :nodoc:
  971. "remove text and leave code (useful when debugging)"
  972. end
  973. def add_text(src, text)
  974. src << ("\n" * text.count("\n"))
  975. if text[-1] != ?\n
  976. text =~ /^(.*?)\z/
  977. src << (' ' * $1.length)
  978. end
  979. end
  980. end
  981. ##
  982. ## remove code and leave text, especially useful when validating HTML tags.
  983. ##
  984. ## ex.
  985. ## $ erubis -s -E NoCode file.eruby | tidy -errors
  986. ##
  987. ## this is language independent.
  988. ##
  989. module NoCodeEnhancer
  990. def self.desc # :nodoc:
  991. "remove code and leave text (useful when validating HTML)"
  992. end
  993. def add_preamble(src)
  994. end
  995. def add_postamble(src)
  996. end
  997. def add_text(src, text)
  998. src << text
  999. end
  1000. def add_expr(src, code, indicator)
  1001. src << "\n" * code.count("\n")
  1002. end
  1003. def add_stmt(src, code)
  1004. src << "\n" * code.count("\n")
  1005. end
  1006. end
  1007. ##
  1008. ## get convert faster, but spaces around '<%...%>' are not trimmed.
  1009. ##
  1010. ## this is language-independent.
  1011. ##
  1012. module SimplifyEnhancer
  1013. def self.desc # :nodoc:
  1014. "get convert faster but leave spaces around '<% %>'"
  1015. end
  1016. #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  1017. SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
  1018. def convert(input)
  1019. src = ""
  1020. add_preamble(src)
  1021. #regexp = pattern_regexp(@pattern)
  1022. pos = 0
  1023. input.scan(SIMPLE_REGEXP) do |indicator, code|
  1024. match = Regexp.last_match
  1025. index = match.begin(0)
  1026. text = input[pos, index - pos]
  1027. pos = match.end(0)
  1028. add_text(src, text)
  1029. if !indicator # <% %>
  1030. add_stmt(src, code)
  1031. elsif indicator[0] == ?\# # <%# %>
  1032. n = code.count("\n")
  1033. add_stmt(src, "\n" * n)
  1034. else # <%= %>
  1035. add_expr(src, code, indicator)
  1036. end
  1037. end
  1038. #rest = $' || input # ruby1.8
  1039. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1040. add_text(src, rest)
  1041. add_postamble(src)
  1042. return src
  1043. end
  1044. end
  1045. ##
  1046. ## enable to use other embedded expression pattern (default is '\[= =\]').
  1047. ##
  1048. ## notice! this is an experimental. spec may change in the future.
  1049. ##
  1050. ## ex.
  1051. ## input = <<END
  1052. ## <% for item in list %>
  1053. ## <%= item %> : <%== item %>
  1054. ## [= item =] : [== item =]
  1055. ## <% end %>
  1056. ## END
  1057. ##
  1058. ## class BiPatternEruby
  1059. ## include BiPatternEnhancer
  1060. ## end
  1061. ## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
  1062. ## list = ['<a>', 'b&b', '"c"']
  1063. ## print eruby.result(binding())
  1064. ##
  1065. ## ## output
  1066. ## <a> : &lt;a&gt;
  1067. ## <a> : &lt;a&gt;
  1068. ## b&b : b&amp;b
  1069. ## b&b : b&amp;b
  1070. ## "c" : &quot;c&quot;
  1071. ## "c" : &quot;c&quot;
  1072. ##
  1073. ## this is language independent.
  1074. ##
  1075. module BiPatternEnhancer
  1076. def self.desc # :nodoc:
  1077. "another embedded expression pattern (default '\[= =\]')."
  1078. end
  1079. def initialize(input, properties={})
  1080. self.bipattern = properties[:bipattern] # or '\$\{ \}'
  1081. super
  1082. end
  1083. ## when pat is nil then '\[= =\]' is used
  1084. def bipattern=(pat) # :nodoc:
  1085. @bipattern = pat || '\[= =\]'
  1086. pre, post = @bipattern.split()
  1087. @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
  1088. end
  1089. def add_text(src, text)
  1090. return unless text
  1091. m = nil
  1092. text.scan(@bipattern_regexp) do |txt, indicator, code|
  1093. m = Regexp.last_match
  1094. super(src, txt)
  1095. add_expr(src, code, '=' + indicator)
  1096. end
  1097. #rest = $' || text # ruby1.8
  1098. rest = m ? text[m.end(0)..-1] : text # ruby1.9
  1099. super(src, rest)
  1100. end
  1101. end
  1102. ##
  1103. ## regards lines starting with '^[ \t]*%' as program code
  1104. ##
  1105. ## in addition you can specify prefix character (default '%')
  1106. ##
  1107. ## this is language-independent.
  1108. ##
  1109. module PrefixedLineEnhancer
  1110. def self.desc # :nodoc:
  1111. "regard lines matched to '^[ \t]*%' as program code"
  1112. end
  1113. def init_generator(properties={})
  1114. super
  1115. @prefixchar = properties[:prefixchar]
  1116. end
  1117. def add_text(src, text)
  1118. unless @prefixrexp
  1119. @prefixchar ||= '%'
  1120. @prefixrexp = Regexp.compile("^([ \\t]*)\\#{@prefixchar}(.*?\\r?\\n)")
  1121. end
  1122. pos = 0
  1123. text2 = ''
  1124. text.scan(@prefixrexp) do
  1125. space = $1
  1126. line = $2
  1127. space, line = '', $1 unless $2
  1128. match = Regexp.last_match
  1129. len = match.begin(0) - pos
  1130. str = text[pos, len]
  1131. pos = match.end(0)
  1132. if text2.empty?
  1133. text2 = str
  1134. else
  1135. text2 << str
  1136. end
  1137. if line[0, 1] == @prefixchar
  1138. text2 << space << line
  1139. else
  1140. super(src, text2)
  1141. text2 = ''
  1142. add_stmt(src, space + line)
  1143. end
  1144. end
  1145. #rest = pos == 0 ? text : $' # ruby1.8
  1146. rest = pos == 0 ? text : text[pos..-1] # ruby1.9
  1147. unless text2.empty?
  1148. text2 << rest if rest
  1149. rest = text2
  1150. end
  1151. super(src, rest)
  1152. end
  1153. end
  1154. ##
  1155. ## regards lines starting with '%' as program code
  1156. ##
  1157. ## this is for compatibility to eruby and ERB.
  1158. ##
  1159. ## this is language-independent.
  1160. ##
  1161. module PercentLineEnhancer
  1162. include PrefixedLineEnhancer
  1163. def self.desc # :nodoc:
  1164. "regard lines starting with '%' as program code"
  1165. end
  1166. #--
  1167. #def init_generator(properties={})
  1168. # super
  1169. # @prefixchar = '%'
  1170. # @prefixrexp = /^\%(.*?\r?\n)/
  1171. #end
  1172. #++
  1173. def add_text(src, text)
  1174. unless @prefixrexp
  1175. @prefixchar = '%'
  1176. @prefixrexp = /^\%(.*?\r?\n)/
  1177. end
  1178. super(src, text)
  1179. end
  1180. end
  1181. ##
  1182. ## [experimental] allow header and footer in eRuby script
  1183. ##
  1184. ## ex.
  1185. ## ====================
  1186. ## ## without header and footer
  1187. ## $ cat ex1.eruby
  1188. ## <% def list_items(list) %>
  1189. ## <% for item in list %>
  1190. ## <li><%= item %></li>
  1191. ## <% end %>
  1192. ## <% end %>
  1193. ##
  1194. ## $ erubis -s ex1.eruby
  1195. ## _buf = []; def list_items(list)
  1196. ## ; for item in list
  1197. ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
  1198. ## '; end
  1199. ## ; end
  1200. ## ;
  1201. ## _buf.join
  1202. ##
  1203. ## ## with header and footer
  1204. ## $ cat ex2.eruby
  1205. ## <!--#header:
  1206. ## def list_items(list)
  1207. ## #-->
  1208. ## <% for item in list %>
  1209. ## <li><%= item %></li>
  1210. ## <% end %>
  1211. ## <!--#footer:
  1212. ## end
  1213. ## #-->
  1214. ##
  1215. ## $ erubis -s -c HeaderFooterEruby ex4.eruby
  1216. ##
  1217. ## def list_items(list)
  1218. ## _buf = []; _buf << '
  1219. ## '; for item in list
  1220. ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
  1221. ## '; end
  1222. ## ; _buf << '
  1223. ## ';
  1224. ## _buf.join
  1225. ## end
  1226. ##
  1227. ## ====================
  1228. ##
  1229. ## this is language-independent.
  1230. ##
  1231. module HeaderFooterEnhancer
  1232. def self.desc # :nodoc:
  1233. "allow header/footer in document (ex. '<!--#header: #-->')"
  1234. end
  1235. HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
  1236. def add_text(src, text)
  1237. m = nil
  1238. text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
  1239. m = Regexp.last_match
  1240. flag_trim = @trim && lspace && rspace
  1241. super(src, txt)
  1242. content = "#{lspace}#{content}#{rspace}" if flag_trim
  1243. super(src, lspace) if !flag_trim && lspace
  1244. instance_variable_set("@#{word}", content)
  1245. super(src, rspace) if !flag_trim && rspace
  1246. end
  1247. #rest = $' || text # ruby1.8
  1248. rest = m ? text[m.end(0)..-1] : text # ruby1.9
  1249. super(src, rest)
  1250. end
  1251. attr_accessor :header, :footer
  1252. def convert(input)
  1253. source = super
  1254. return @src = "#{@header}#{source}#{@footer}"
  1255. end
  1256. end
  1257. ##
  1258. ## delete indentation of HTML.
  1259. ##
  1260. ## this is language-independent.
  1261. ##
  1262. module DeleteIndentEnhancer
  1263. def self.desc # :nodoc:
  1264. "delete indentation of HTML."
  1265. end
  1266. def convert_input(src, input)
  1267. input = input.gsub(/^[ \t]+</, '<')
  1268. super(src, input)
  1269. end
  1270. end
  1271. ##
  1272. ## convert "<h1><%=title%></h1>" into "_buf << %Q`<h1>#{title}</h1>`"
  1273. ##
  1274. ## this is only for Eruby.
  1275. ##
  1276. module InterpolationEnhancer
  1277. def self.desc # :nodoc:
  1278. "convert '<p><%=text%></p>' into '_buf << %Q`<p>\#{text}</p>`'"
  1279. end
  1280. def convert_input(src, input)
  1281. pat = @pattern
  1282. regexp = pat.nil? || pat == '<% %>' ? Basic::Converter::DEFAULT_REGEXP : pattern_regexp(pat)
  1283. pos = 0
  1284. is_bol = true # is beginning of line
  1285. str = ''
  1286. input.scan(regexp) do |indicator, code, tailch, rspace|
  1287. match = Regexp.last_match()
  1288. len = match.begin(0) - pos
  1289. text = input[pos, len]
  1290. pos = match.end(0)
  1291. ch = indicator ? indicator[0] : nil
  1292. lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
  1293. is_bol = rspace ? true : false
  1294. _add_text_to_str(str, text)
  1295. ## * when '<%= %>', do nothing
  1296. ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
  1297. if ch == ?= # <%= %>
  1298. rspace = nil if tailch && !tailch.empty?
  1299. str << lspace if lspace
  1300. add_expr(str, code, indicator)
  1301. str << rspace if rspace
  1302. elsif ch == ?\# # <%# %>
  1303. n = code.count("\n") + (rspace ? 1 : 0)
  1304. if @trim && lspace && rspace
  1305. add_text(src, str)
  1306. str = ''
  1307. add_stmt(src, "\n" * n)
  1308. else
  1309. str << lspace if lspace
  1310. add_text(src, str)
  1311. str = ''
  1312. add_stmt(src, "\n" * n)
  1313. str << rspace if rspace
  1314. end
  1315. else # <% %>
  1316. if @trim && lspace && rspace
  1317. add_text(src, str)
  1318. str = ''
  1319. add_stmt(src, "#{lspace}#{code}#{rspace}")
  1320. else
  1321. str << lspace if lspace
  1322. add_text(src, str)
  1323. str = ''
  1324. add_stmt(src, code)
  1325. str << rspace if rspace
  1326. end
  1327. end
  1328. end
  1329. #rest = $' || input # ruby1.8
  1330. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1331. _add_text_to_str(str, rest)
  1332. add_text(src, str)
  1333. end
  1334. def add_text(src, text)
  1335. return if !text || text.empty?
  1336. #src << " _buf << %Q`" << text << "`;"
  1337. if text[-1] == ?\n
  1338. text[-1] = "\\n"
  1339. src << " #{@bufvar} << %Q`#{text}`\n"
  1340. else
  1341. src << " #{@bufvar} << %Q`#{text}`;"
  1342. end
  1343. end
  1344. def _add_text_to_str(str, text)
  1345. return if !text || text.empty?
  1346. str << text.gsub(/[`\#\\]/, '\\\\\&')
  1347. end
  1348. def add_expr_escaped(str, code)
  1349. str << "\#{#{escaped_expr(code)}}"
  1350. end
  1351. def add_expr_literal(str, code)
  1352. str << "\#{#{code}}"
  1353. end
  1354. end
  1355. end
  1356. #--end of require 'erubis/enhancer'
  1357. #require 'erubis/tiny'
  1358. #--begin of require 'erubis/engine/eruby'
  1359. ##
  1360. ## $Release: 2.7.0 $
  1361. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1362. ##
  1363. #--already included require 'erubis/engine'
  1364. #--already included require 'erubis/enhancer'
  1365. module Erubis
  1366. ##
  1367. ## code generator for Ruby
  1368. ##
  1369. module RubyGenerator
  1370. include Generator
  1371. #include ArrayBufferEnhancer
  1372. include StringBufferEnhancer
  1373. def init_generator(properties={})
  1374. super
  1375. @escapefunc ||= "Erubis::XmlHelper.escape_xml"
  1376. @bufvar = properties[:bufvar] || "_buf"
  1377. end
  1378. def self.supported_properties() # :nodoc:
  1379. return []
  1380. end
  1381. def escape_text(text)
  1382. text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
  1383. end
  1384. def escaped_expr(code)
  1385. return "#{@escapefunc}(#{code})"
  1386. end
  1387. #--
  1388. #def add_preamble(src)
  1389. # src << "#{@bufvar} = [];"
  1390. #end
  1391. #++
  1392. def add_text(src, text)
  1393. src << " #{@bufvar} << '" << escape_text(text) << "';" unless text.empty?
  1394. end
  1395. def add_stmt(src, code)
  1396. #src << code << ';'
  1397. src << code
  1398. src << ';' unless code[-1] == ?\n
  1399. end
  1400. def add_expr_literal(src, code)
  1401. src << " #{@bufvar} << (" << code << ').to_s;'
  1402. end
  1403. def add_expr_escaped(src, code)
  1404. src << " #{@bufvar} << " << escaped_expr(code) << ';'
  1405. end
  1406. def add_expr_debug(src, code)
  1407. code.strip!
  1408. s = (code.dump =~ /\A"(.*)"\z/) && $1
  1409. src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
  1410. end
  1411. #--
  1412. #def add_postamble(src)
  1413. # src << "\n#{@bufvar}.join\n"
  1414. #end
  1415. #++
  1416. end
  1417. ##
  1418. ## engine for Ruby
  1419. ##
  1420. class Eruby < Basic::Engine
  1421. include RubyEvaluator
  1422. include RubyGenerator
  1423. end
  1424. ##
  1425. ## fast engine for Ruby
  1426. ##
  1427. class FastEruby < Eruby
  1428. include InterpolationEnhancer
  1429. end
  1430. ##
  1431. ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
  1432. ##
  1433. class EscapedEruby < Eruby
  1434. include EscapeEnhancer
  1435. end
  1436. ##
  1437. ## sanitize expression (<%= ... %>) by default
  1438. ##
  1439. ## this is equivalent to EscapedEruby and is prepared only for compatibility.
  1440. ##
  1441. class XmlEruby < Eruby
  1442. include EscapeEnhancer
  1443. end
  1444. class PI::Eruby < PI::Engine
  1445. include RubyEvaluator
  1446. include RubyGenerator
  1447. def init_converter(properties={})
  1448. @pi = 'rb'
  1449. super(properties)
  1450. end
  1451. end
  1452. end
  1453. #--end of require 'erubis/engine/eruby'
  1454. #require 'erubis/engine/enhanced' # enhanced eruby engines
  1455. #require 'erubis/engine/optimized' # generates optimized ruby code
  1456. #require 'erubis/engine/ephp'
  1457. #require 'erubis/engine/ec'
  1458. #require 'erubis/engine/ejava'
  1459. #require 'erubis/engine/escheme'
  1460. #require 'erubis/engine/eperl'
  1461. #require 'erubis/engine/ejavascript'
  1462. #--begin of require 'erubis/local-setting'
  1463. ##
  1464. ## $Release: 2.7.0 $
  1465. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1466. ##
  1467. ##
  1468. ## you can add site-local settings here.
  1469. ## this files is required by erubis.rb
  1470. ##
  1471. #--end of require 'erubis/local-setting'
  1472. #--end of require 'erubis'
  1473. #--begin of require 'erubis/tiny'
  1474. ##
  1475. ## $Release: 2.7.0 $
  1476. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1477. ##
  1478. module Erubis
  1479. ##
  1480. ## tiny and the simplest implementation of eRuby
  1481. ##
  1482. ## ex.
  1483. ## eruby = TinyEruby.new(File.read('example.rhtml'))
  1484. ## print eruby.src # print ruby code
  1485. ## print eruby.result(binding()) # eval ruby code with Binding object
  1486. ## print eruby.evalute(context) # eval ruby code with context object
  1487. ##
  1488. class TinyEruby
  1489. def initialize(input=nil)
  1490. @src = convert(input) if input
  1491. end
  1492. attr_reader :src
  1493. EMBEDDED_PATTERN = /<%(=+|\#)?(.*?)-?%>/m
  1494. def convert(input)
  1495. src = "_buf = '';" # preamble
  1496. pos = 0
  1497. input.scan(EMBEDDED_PATTERN) do |indicator, code|
  1498. m = Regexp.last_match
  1499. text = input[pos...m.begin(0)]
  1500. pos = m.end(0)
  1501. #src << " _buf << '" << escape_text(text) << "';"
  1502. text.gsub!(/['\\]/, '\\\\\&')
  1503. src << " _buf << '" << text << "';" unless text.empty?
  1504. if !indicator # <% %>
  1505. src << code << ";"
  1506. elsif indicator == '#' # <%# %>
  1507. src << ("\n" * code.count("\n"))
  1508. else # <%= %>
  1509. src << " _buf << (" << code << ").to_s;"
  1510. end
  1511. end
  1512. #rest = $' || input # ruby1.8
  1513. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1514. #src << " _buf << '" << escape_text(rest) << "';"
  1515. rest.gsub!(/['\\]/, '\\\\\&')
  1516. src << " _buf << '" << rest << "';" unless rest.empty?
  1517. src << "\n_buf.to_s\n" # postamble
  1518. return src
  1519. end
  1520. #def escape_text(text)
  1521. # return text.gsub!(/['\\]/, '\\\\\&') || text
  1522. #end
  1523. def result(_binding=TOPLEVEL_BINDING)
  1524. eval @src, _binding
  1525. end
  1526. def evaluate(_context=Object.new)
  1527. if _context.is_a?(Hash)
  1528. _obj = Object.new
  1529. _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
  1530. _context = _obj
  1531. end
  1532. _context.instance_eval @src
  1533. end
  1534. end
  1535. module PI
  1536. end
  1537. class PI::TinyEruby
  1538. def initialize(input=nil, options={})
  1539. @escape = options[:escape] || 'Erubis::XmlHelper.escape_xml'
  1540. @src = convert(input) if input
  1541. end
  1542. attr_reader :src
  1543. EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|@(!+)?\{(.*?)\}@/m
  1544. def convert(input)
  1545. src = "_buf = '';" # preamble
  1546. pos = 0
  1547. input.scan(EMBEDDED_PATTERN) do |lspace, stmt, rspace, indicator, expr|
  1548. match = Regexp.last_match
  1549. len = match.begin(0) - pos
  1550. text = input[pos, len]
  1551. pos = match.end(0)
  1552. #src << " _buf << '" << escape_text(text) << "';"
  1553. text.gsub!(/['\\]/, '\\\\\&')
  1554. src << " _buf << '" << text << "';" unless text.empty?
  1555. if stmt # <?rb ... ?>
  1556. if lspace && rspace
  1557. src << "#{lspace}#{stmt}#{rspace}"
  1558. else
  1559. src << " _buf << '" << lspace << "';" if lspace
  1560. src << stmt << ";"
  1561. src << " _buf << '" << rspace << "';" if rspace
  1562. end
  1563. else # ${...}, $!{...}
  1564. if !indicator
  1565. src << " _buf << " << @escape << "(" << expr << ");"
  1566. elsif indicator == '!'
  1567. src << " _buf << (" << expr << ").to_s;"
  1568. end
  1569. end
  1570. end
  1571. #rest = $' || input # ruby1.8
  1572. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1573. #src << " _buf << '" << escape_text(rest) << "';"
  1574. rest.gsub!(/['\\]/, '\\\\\&')
  1575. src << " _buf << '" << rest << "';" unless rest.empty?
  1576. src << "\n_buf.to_s\n" # postamble
  1577. return src
  1578. end
  1579. #def escape_text(text)
  1580. # return text.gsub!(/['\\]/, '\\\\\&') || text
  1581. #end
  1582. def result(_binding=TOPLEVEL_BINDING)
  1583. eval @src, _binding
  1584. end
  1585. def evaluate(_context=Object.new)
  1586. if _context.is_a?(Hash)
  1587. _obj = Object.new
  1588. _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
  1589. _context = _obj
  1590. end
  1591. _context.instance_eval @src
  1592. end
  1593. end
  1594. end
  1595. #--end of require 'erubis/tiny'
  1596. #--begin of require 'erubis/engine/enhanced'
  1597. ##
  1598. ## $Release: 2.7.0 $
  1599. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1600. ##
  1601. #--already included require 'erubis/enhancer'
  1602. #--already included require 'erubis/engine/eruby'
  1603. module Erubis
  1604. #--
  1605. ## moved to engine/ruby.rb
  1606. #class EscapedEruby < Eruby
  1607. # include EscapeEnhancer
  1608. #end
  1609. #++
  1610. #--
  1611. ### (obsolete)
  1612. #class FastEruby < Eruby
  1613. # include FastEnhancer
  1614. #end
  1615. #++
  1616. class StdoutEruby < Eruby
  1617. include StdoutEnhancer
  1618. end
  1619. class PrintOutEruby < Eruby
  1620. include PrintOutEnhancer
  1621. end
  1622. class PrintEnabledEruby < Eruby
  1623. include PrintEnabledEnhancer
  1624. end
  1625. class ArrayEruby < Eruby
  1626. include ArrayEnhancer
  1627. end
  1628. class ArrayBufferEruby < Eruby
  1629. include ArrayBufferEnhancer
  1630. end
  1631. class StringBufferEruby < Eruby
  1632. include StringBufferEnhancer
  1633. end
  1634. class StringIOEruby < Eruby
  1635. include StringIOEnhancer
  1636. end
  1637. class ErboutEruby < Eruby
  1638. include ErboutEnhancer
  1639. end
  1640. class NoTextEruby < Eruby
  1641. include NoTextEnhancer
  1642. end
  1643. class NoCodeEruby < Eruby
  1644. include NoCodeEnhancer
  1645. end
  1646. class SimplifiedEruby < Eruby
  1647. include SimplifyEnhancer
  1648. end
  1649. class StdoutSimplifiedEruby < Eruby
  1650. include StdoutEnhancer
  1651. include SimplifyEnhancer
  1652. end
  1653. class PrintOutSimplifiedEruby < Eruby
  1654. include PrintOutEnhancer
  1655. include SimplifyEnhancer
  1656. end
  1657. class BiPatternEruby < Eruby
  1658. include BiPatternEnhancer
  1659. end
  1660. class PercentLineEruby < Eruby
  1661. include PercentLineEnhancer
  1662. end
  1663. class PrefixedLineEruby < Eruby
  1664. include PrefixedLineEnhancer
  1665. end
  1666. class HeaderFooterEruby < Eruby
  1667. include HeaderFooterEnhancer
  1668. end
  1669. class DeleteIndentEruby < Eruby
  1670. include DeleteIndentEnhancer
  1671. end
  1672. class InterpolationEruby < Eruby
  1673. include InterpolationEnhancer
  1674. end
  1675. end
  1676. #--end of require 'erubis/engine/enhanced'
  1677. #--begin of require 'erubis/engine/optimized'
  1678. ##
  1679. ## $Release: 2.7.0 $
  1680. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1681. ##
  1682. #--already included require 'erubis/engine/eruby'
  1683. module Erubis
  1684. module OptimizedGenerator
  1685. include Generator
  1686. def self.supported_properties() # :nodoc:
  1687. return []
  1688. end
  1689. def init_generator(properties={})
  1690. super
  1691. @escapefunc ||= "Erubis::XmlHelper.escape_xml"
  1692. @initialized = false
  1693. @prev_is_expr = false
  1694. end
  1695. protected
  1696. def escape_text(text)
  1697. text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
  1698. end
  1699. def escaped_expr(code)
  1700. @escapefunc ||= 'Erubis::XmlHelper.escape_xml'
  1701. return "#{@escapefunc}(#{code})"
  1702. end
  1703. def switch_to_expr(src)
  1704. return if @prev_is_expr
  1705. @prev_is_expr = true
  1706. src << ' _buf'
  1707. end
  1708. def switch_to_stmt(src)
  1709. return unless @prev_is_expr
  1710. @prev_is_expr = false
  1711. src << ';'
  1712. end
  1713. def add_preamble(src)
  1714. #@initialized = false
  1715. #@prev_is_expr = false
  1716. end
  1717. def add_text(src, text)
  1718. return if text.empty?
  1719. if @initialized
  1720. switch_to_expr(src)
  1721. src << " << '" << escape_text(text) << "'"
  1722. else
  1723. src << "_buf = '" << escape_text(text) << "';"
  1724. @initialized = true
  1725. end
  1726. end
  1727. def add_stmt(src, code)
  1728. switch_to_stmt(src) if @initialized
  1729. #super
  1730. src << code
  1731. src << ';' unless code[-1] == ?\n
  1732. end
  1733. def add_expr_literal(src, code)
  1734. unless @initialized; src << "_buf = ''"; @initialized = true; end
  1735. switch_to_expr(src)
  1736. src << " << (" << code << ").to_s"
  1737. end
  1738. def add_expr_escaped(src, code)
  1739. unless @initialized; src << "_buf = ''"; @initialized = true; end
  1740. switch_to_expr(src)
  1741. src << " << " << escaped_expr(code)
  1742. end
  1743. def add_expr_debug(src, code)
  1744. code.strip!
  1745. s = (code.dump =~ /\A"(.*)"\z/) && $1
  1746. src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
  1747. end
  1748. def add_postamble(src)
  1749. #super if @initialized
  1750. src << "\n_buf\n" if @initialized
  1751. end
  1752. end # end of class OptimizedEruby
  1753. ##
  1754. ## Eruby class which generates optimized ruby code
  1755. ##
  1756. class OptimizedEruby < Basic::Engine # Eruby
  1757. include RubyEvaluator
  1758. include OptimizedGenerator
  1759. def init_converter(properties={})
  1760. @pi = 'rb'
  1761. super(properties)
  1762. end
  1763. end
  1764. ##
  1765. ## XmlEruby class which generates optimized ruby code
  1766. ##
  1767. class OptimizedXmlEruby < OptimizedEruby
  1768. include EscapeEnhancer
  1769. def add_expr_debug(src, code)
  1770. switch_to_stmt(src) if indicator == '===' && !@initialized
  1771. super
  1772. end
  1773. end # end of class OptimizedXmlEruby
  1774. end
  1775. #--end of require 'erubis/engine/optimized'
  1776. #--already included require 'erubis/engine/eruby'
  1777. #--begin of require 'erubis/engine/ephp'
  1778. ##
  1779. ## $Release: 2.7.0 $
  1780. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1781. ##
  1782. #--already included require 'erubis/engine'
  1783. #--already included require 'erubis/enhancer'
  1784. module Erubis
  1785. module PhpGenerator
  1786. include Generator
  1787. def self.supported_properties() # :nodoc:
  1788. return []
  1789. end
  1790. def init_generator(properties={})
  1791. super
  1792. @escapefunc ||= 'htmlspecialchars'
  1793. end
  1794. def add_preamble(src)
  1795. # empty
  1796. end
  1797. def escape_text(text)
  1798. return text.gsub!(/<\?xml\b/, '<<?php ?>?xml') || text
  1799. end
  1800. def add_text(src, text)
  1801. src << escape_text(text)
  1802. end
  1803. def add_expr_literal(src, code)
  1804. code.strip!
  1805. src << "<?php echo #{code}; ?>"
  1806. end
  1807. def add_expr_escaped(src, code)
  1808. add_expr_literal(src, escaped_expr(code))
  1809. end
  1810. def add_expr_debug(src, code)
  1811. code.strip!
  1812. s = code.gsub(/\'/, "\\'")
  1813. src << "<?php error_log('*** debug: #{s}='.(#{code}), 0); ?>"
  1814. end
  1815. def add_stmt(src, code)
  1816. src << "<?php"
  1817. src << " " if code[0] != ?\ #
  1818. if code[-1] == ?\n
  1819. code.chomp!
  1820. src << code << "?>\n"
  1821. else
  1822. src << code << "?>"
  1823. end
  1824. end
  1825. def add_postamble(src)
  1826. # empty
  1827. end
  1828. end
  1829. ##
  1830. ## engine for PHP
  1831. ##
  1832. class Ephp < Basic::Engine
  1833. include PhpGenerator
  1834. end
  1835. class EscapedEphp < Ephp
  1836. include EscapeEnhancer
  1837. end
  1838. #class XmlEphp < Ephp
  1839. # include EscapeEnhancer
  1840. #end
  1841. class PI::Ephp < PI::Engine
  1842. include PhpGenerator
  1843. def init_converter(properties={})
  1844. @pi = 'php'
  1845. super(properties)
  1846. end
  1847. end
  1848. end
  1849. #--end of require 'erubis/engine/ephp'
  1850. #--begin of require 'erubis/engine/ec'
  1851. ##
  1852. ## $Release: 2.7.0 $
  1853. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1854. ##
  1855. #--already included require 'erubis/engine'
  1856. #--already included require 'erubis/enhancer'
  1857. module Erubis
  1858. module CGenerator
  1859. include Generator
  1860. def self.supported_properties() # :nodoc:
  1861. return [
  1862. [:indent, '', "indent spaces (ex. ' ')"],
  1863. [:out, 'stdout', "output file pointer name"],
  1864. ]
  1865. end
  1866. def init_generator(properties={})
  1867. super
  1868. @escapefunc ||= "escape"
  1869. @indent = properties[:indent] || ''
  1870. @out = properties[:out] || 'stdout'
  1871. end
  1872. def add_preamble(src)
  1873. src << "#line 1 \"#{self.filename}\"\n" if self.filename
  1874. end
  1875. def escape_text(text)
  1876. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  1877. text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] }
  1878. return text
  1879. end
  1880. def escaped_expr(code)
  1881. return "#{@escapefunc}(#{code.strip}, #{@out})"
  1882. end
  1883. def add_text(src, text)
  1884. return if text.empty?
  1885. src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
  1886. src << "fputs("
  1887. i = 0
  1888. text.each_line do |line|
  1889. src << "\n" << @indent << ' ' if i > 0
  1890. i += 1
  1891. src << '"' << escape_text(line) << '"'
  1892. end
  1893. src << ", #{@out});" #<< (text[-1] == ?\n ? "\n" : "")
  1894. src << "\n" if text[-1] == ?\n
  1895. end
  1896. def add_stmt(src, code)
  1897. src << code
  1898. end
  1899. def add_expr_literal(src, code)
  1900. src << @indent if src.empty? || src[-1] == ?\n
  1901. src << " fprintf(#{@out}, " << code.strip << ');'
  1902. end
  1903. def add_expr_escaped(src, code)
  1904. src << @indent if src.empty? || src[-1] == ?\n
  1905. src << ' ' << escaped_expr(code) << ';'
  1906. end
  1907. def add_expr_debug(src, code)
  1908. code.strip!
  1909. s = nil
  1910. if code =~ /\A\".*?\"\s*,\s*(.*)/
  1911. s = $1.gsub(/[%"]/, '\\\1') + '='
  1912. end
  1913. src << @indent if src.empty? || src[-1] == ?\n
  1914. src << " fprintf(stderr, \"*** debug: #{s}\" #{code});"
  1915. end
  1916. def add_postamble(src)
  1917. # empty
  1918. end
  1919. end
  1920. ##
  1921. ## engine for C
  1922. ##
  1923. class Ec < Basic::Engine
  1924. include CGenerator
  1925. end
  1926. class EscapedEc < Ec
  1927. include EscapeEnhancer
  1928. end
  1929. #class XmlEc < Ec
  1930. # include EscapeEnhancer
  1931. #end
  1932. class PI::Ec < PI::Engine
  1933. include CGenerator
  1934. def init_converter(properties={})
  1935. @pi = 'c'
  1936. super(properties)
  1937. end
  1938. end
  1939. end
  1940. #--end of require 'erubis/engine/ec'
  1941. #--begin of require 'erubis/engine/ecpp'
  1942. ##
  1943. ## $Release: 2.7.0 $
  1944. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  1945. ##
  1946. #--already included require 'erubis/engine'
  1947. #--already included require 'erubis/enhancer'
  1948. module Erubis
  1949. module CppGenerator
  1950. include Generator
  1951. def self.supported_properties() # :nodoc:
  1952. return [
  1953. [:indent, '', "indent spaces (ex. ' ')"],
  1954. [:bufvar, '_buf', "buffer variable name"],
  1955. ]
  1956. end
  1957. def init_generator(properties={})
  1958. super
  1959. @escapefunc ||= "escape"
  1960. @indent = properties[:indent] || ''
  1961. @bufvar = properties[:bufvar] || '_buf'
  1962. end
  1963. def add_preamble(src)
  1964. src << "#line 1 \"#{self.filename}\"\n" if self.filename
  1965. end
  1966. def escape_text(text)
  1967. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  1968. text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] }
  1969. return text
  1970. end
  1971. def escaped_expr(code)
  1972. return "#{@escapefunc}(#{code.strip})"
  1973. end
  1974. def add_text(src, text)
  1975. return if text.empty?
  1976. src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
  1977. src << "_buf << "
  1978. i = 0
  1979. text.each_line do |line|
  1980. src << "\n" << @indent << " " if i > 0
  1981. i += 1
  1982. src << '"' << escape_text(line) << '"'
  1983. end
  1984. src << ";" #<< (text[-1] == ?\n ? "\n" : "")
  1985. src << "\n" if text[-1] == ?\n
  1986. end
  1987. def add_stmt(src, code)
  1988. src << code
  1989. end
  1990. def add_expr_literal(src, code)
  1991. src << @indent if src.empty? || src[-1] == ?\n
  1992. src << " _buf << (" << code.strip << ");"
  1993. end
  1994. def add_expr_escaped(src, code)
  1995. src << @indent if src.empty? || src[-1] == ?\n
  1996. src << ' ' << escaped_expr(code) << ';'
  1997. end
  1998. def add_expr_debug(src, code)
  1999. code.strip!
  2000. src << @indent if src.empty? || src[-1] == ?\n
  2001. src << " std::cerr << \"*** debug: #{code.gsub(/(")/, '\\\&')}=\" << (#{code});"
  2002. end
  2003. def add_postamble(src)
  2004. # empty
  2005. end
  2006. end
  2007. ##
  2008. ## engine for C
  2009. ##
  2010. class Ecpp < Basic::Engine
  2011. include CppGenerator
  2012. end
  2013. class EscapedEcpp < Ecpp
  2014. include EscapeEnhancer
  2015. end
  2016. #class XmlEcpp < Ecpp
  2017. # include EscapeEnhancer
  2018. #end
  2019. class PI::Ecpp < PI::Engine
  2020. include CppGenerator
  2021. def init_converter(properties={})
  2022. @pi = 'cpp'
  2023. super(properties)
  2024. end
  2025. end
  2026. end
  2027. #--end of require 'erubis/engine/ecpp'
  2028. #--begin of require 'erubis/engine/ejava'
  2029. ##
  2030. ## $Release: 2.7.0 $
  2031. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  2032. ##
  2033. #--already included require 'erubis/engine'
  2034. #--already included require 'erubis/enhancer'
  2035. module Erubis
  2036. module JavaGenerator
  2037. include Generator
  2038. def self.supported_properties() # :nodoc:
  2039. return [
  2040. [:indent, '', "indent spaces (ex. ' ')"],
  2041. [:bufvar, '_buf', "output buffer variable name"],
  2042. [:bufclass, 'StringBuffer', "output buffer class (ex. 'StringBuilder')"],
  2043. ]
  2044. end
  2045. def init_generator(properties={})
  2046. super
  2047. @escapefunc ||= 'escape'
  2048. @indent = properties[:indent] || ''
  2049. @bufvar = properties[:bufvar] || '_buf'
  2050. @bufclass = properties[:bufclass] || 'StringBuffer'
  2051. end
  2052. def add_preamble(src)
  2053. src << "#{@indent}#{@bufclass} #{@bufvar} = new #{@bufclass}();"
  2054. end
  2055. def escape_text(text)
  2056. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  2057. return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
  2058. end
  2059. def add_text(src, text)
  2060. return if text.empty?
  2061. src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
  2062. src << @bufvar << ".append("
  2063. i = 0
  2064. text.each_line do |line|
  2065. src << "\n" << @indent << ' + ' if i > 0
  2066. i += 1
  2067. src << '"' << escape_text(line) << '"'
  2068. end
  2069. src << ");" << (text[-1] == ?\n ? "\n" : "")
  2070. end
  2071. def add_stmt(src, code)
  2072. src << code
  2073. end
  2074. def add_expr_literal(src, code)
  2075. src << @indent if src.empty? || src[-1] == ?\n
  2076. code.strip!
  2077. src << " #{@bufvar}.append(#{code});"
  2078. end
  2079. def add_expr_escaped(src, code)
  2080. add_expr_literal(src, escaped_expr(code))
  2081. end
  2082. def add_expr_debug(src, code)
  2083. code.strip!
  2084. src << @indent if src.empty? || src[-1] == ?\n
  2085. src << " System.err.println(\"*** debug: #{code}=\"+(#{code}));"
  2086. end
  2087. def add_postamble(src)
  2088. src << "\n" if src[-1] == ?;
  2089. src << @indent << "return " << @bufvar << ".toString();\n"
  2090. #src << @indent << "System.out.print(" << @bufvar << ".toString());\n"
  2091. end
  2092. end
  2093. ##
  2094. ## engine for Java
  2095. ##
  2096. class Ejava < Basic::Engine
  2097. include JavaGenerator
  2098. end
  2099. class EscapedEjava < Ejava
  2100. include EscapeEnhancer
  2101. end
  2102. #class XmlEjava < Ejava
  2103. # include EscapeEnhancer
  2104. #end
  2105. class PI::Ejava < PI::Engine
  2106. include JavaGenerator
  2107. def init_converter(properties={})
  2108. @pi = 'java'
  2109. super(properties)
  2110. end
  2111. end
  2112. end
  2113. #--end of require 'erubis/engine/ejava'
  2114. #--begin of require 'erubis/engine/escheme'
  2115. ##
  2116. ## $Release: 2.7.0 $
  2117. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  2118. ##
  2119. #--already included require 'erubis/engine'
  2120. #--already included require 'erubis/enhancer'
  2121. module Erubis
  2122. module SchemeGenerator
  2123. include Generator
  2124. def self.supported_properties() # :nodoc:
  2125. return [
  2126. [:func, '_add', "function name (ex. 'display')"],
  2127. ]
  2128. end
  2129. def init_generator(properties={})
  2130. super
  2131. @escapefunc ||= 'escape'
  2132. @func = properties[:func] || '_add' # or 'display'
  2133. end
  2134. def add_preamble(src)
  2135. return unless @func == '_add'
  2136. src << "(let ((_buf '())) " + \
  2137. "(define (_add x) (set! _buf (cons x _buf))) "
  2138. #src << "(let* ((_buf '())" + \
  2139. # " (_add (lambda (x) (set! _buf (cons x _buf))))) "
  2140. end
  2141. def escape_text(text)
  2142. @table_ ||= { '"'=>'\\"', '\\'=>'\\\\' }
  2143. text.gsub!(/["\\]/) { |m| @table_[m] }
  2144. return text
  2145. end
  2146. def escaped_expr(code)
  2147. code.strip!
  2148. return "(#{@escapefunc} #{code})"
  2149. end
  2150. def add_text(src, text)
  2151. return if text.empty?
  2152. t = escape_text(text)
  2153. if t[-1] == ?\n
  2154. t[-1, 1] = ''
  2155. src << "(#{@func} \"" << t << "\\n\")\n"
  2156. else
  2157. src << "(#{@func} \"" << t << '")'
  2158. end
  2159. end
  2160. def add_stmt(src, code)
  2161. src << code
  2162. end
  2163. def add_expr_literal(src, code)
  2164. code.strip!
  2165. src << "(#{@func} #{code})"
  2166. end
  2167. def add_expr_escaped(src, code)
  2168. add_expr_literal(src, escaped_expr(code))
  2169. end
  2170. def add_expr_debug(src, code)
  2171. s = (code.strip! || code).gsub(/\"/, '\\"')
  2172. src << "(display \"*** debug: #{s}=\")(display #{code.strip})(display \"\\n\")"
  2173. end
  2174. def add_postamble(src)
  2175. return unless @func == '_add'
  2176. src << "\n" unless src[-1] == ?\n
  2177. src << " (reverse _buf))\n"
  2178. end
  2179. end
  2180. ##
  2181. ## engine for Scheme
  2182. ##
  2183. class Escheme < Basic::Engine
  2184. include SchemeGenerator
  2185. end
  2186. class EscapedEscheme < Escheme
  2187. include EscapeEnhancer
  2188. end
  2189. #class XmlEscheme < Escheme
  2190. # include EscapeEnhancer
  2191. #end
  2192. class PI::Escheme < PI::Engine
  2193. include SchemeGenerator
  2194. def init_converter(properties={})
  2195. @pi = 'scheme'
  2196. super(properties)
  2197. end
  2198. end
  2199. end
  2200. #--end of require 'erubis/engine/escheme'
  2201. #--begin of require 'erubis/engine/eperl'
  2202. ##
  2203. ## $Release: 2.7.0 $
  2204. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  2205. ##
  2206. #--already included require 'erubis/engine'
  2207. #--already included require 'erubis/enhancer'
  2208. module Erubis
  2209. module PerlGenerator
  2210. include Generator
  2211. def self.supported_properties() # :nodoc:
  2212. return [
  2213. [:func, 'print', "function name"],
  2214. ]
  2215. end
  2216. def init_generator(properties={})
  2217. super
  2218. @escapefunc ||= 'encode_entities'
  2219. @func = properties[:func] || 'print'
  2220. end
  2221. def add_preamble(src)
  2222. src << "use HTML::Entities; ";
  2223. end
  2224. def escape_text(text)
  2225. return text.gsub!(/['\\]/, '\\\\\&') || text
  2226. end
  2227. def add_text(src, text)
  2228. src << @func << "('" << escape_text(text) << "'); " unless text.empty?
  2229. end
  2230. def add_expr_literal(src, code)
  2231. code.strip!
  2232. src << @func << "(" << code << "); "
  2233. end
  2234. def add_expr_escaped(src, code)
  2235. add_expr_literal(src, escaped_expr(code))
  2236. end
  2237. def add_expr_debug(src, code)
  2238. code.strip!
  2239. s = code.gsub(/\'/, "\\'")
  2240. src << @func << "('*** debug: #{code}=', #{code}, \"\\n\");"
  2241. end
  2242. def add_stmt(src, code)
  2243. src << code
  2244. end
  2245. def add_postamble(src)
  2246. src << "\n" unless src[-1] == ?\n
  2247. end
  2248. end
  2249. ##
  2250. ## engine for Perl
  2251. ##
  2252. class Eperl < Basic::Engine
  2253. include PerlGenerator
  2254. end
  2255. class EscapedEperl < Eperl
  2256. include EscapeEnhancer
  2257. end
  2258. #class XmlEperl < Eperl
  2259. # include EscapeEnhancer
  2260. #end
  2261. class PI::Eperl < PI::Engine
  2262. include PerlGenerator
  2263. def init_converter(properties={})
  2264. @pi = 'perl'
  2265. super(properties)
  2266. end
  2267. end
  2268. end
  2269. #--end of require 'erubis/engine/eperl'
  2270. #--begin of require 'erubis/engine/ejavascript'
  2271. ##
  2272. ## $Release: 2.7.0 $
  2273. ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  2274. ##
  2275. #--already included require 'erubis/engine'
  2276. #--already included require 'erubis/enhancer'
  2277. module Erubis
  2278. module JavascriptGenerator
  2279. include Generator
  2280. def self.supported_properties() # :nodoc:
  2281. list = []
  2282. #list << [:indent, '', "indent spaces (ex. ' ')"]
  2283. #list << [:bufvar, '_buf', "output buffer variable name"]
  2284. list << [:docwrite, true, "use 'document.write()' when true"]
  2285. return list
  2286. end
  2287. def init_generator(properties={})
  2288. super
  2289. @escapefunc ||= 'escape'
  2290. @indent = properties[:indent] || ''
  2291. @bufvar = properties[:bufvar] || '_buf'
  2292. @docwrite = properties[:docwrite] != false # '!= false' will be removed in the next release
  2293. end
  2294. def add_preamble(src)
  2295. src << "#{@indent}var #{@bufvar} = [];"
  2296. end
  2297. def escape_text(text)
  2298. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n\\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  2299. return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
  2300. end
  2301. def add_indent(src, indent)
  2302. src << (src.empty? || src[-1] == ?\n ? indent : ' ')
  2303. end
  2304. def add_text(src, text)
  2305. return if text.empty?
  2306. add_indent(src, @indent)
  2307. src << @bufvar << '.push("'
  2308. s = escape_text(text)
  2309. if s[-1] == ?\n
  2310. s[-2, 2] = ''
  2311. src << s << "\");\n"
  2312. else
  2313. src << s << "\");"
  2314. end
  2315. end
  2316. def add_stmt(src, code)
  2317. src << code
  2318. end
  2319. def add_expr_literal(src, code)
  2320. add_indent(src, @indent)
  2321. code.strip!
  2322. src << "#{@bufvar}.push(#{code});"
  2323. end
  2324. def add_expr_escaped(src, code)
  2325. add_expr_literal(src, escaped_expr(code))
  2326. end
  2327. def add_expr_debug(src, code)
  2328. add_indent(src, @indent)
  2329. code.strip!
  2330. src << "alert(\"*** debug: #{code}=\"+(#{code}));"
  2331. end
  2332. def add_postamble(src)
  2333. src << "\n" if src[-1] == ?;
  2334. if @docwrite
  2335. src << @indent << 'document.write(' << @bufvar << ".join(\"\"));\n"
  2336. else
  2337. src << @indent << @bufvar << ".join(\"\");\n"
  2338. end
  2339. end
  2340. end
  2341. ##
  2342. ## engine for JavaScript
  2343. ##
  2344. class Ejavascript < Basic::Engine
  2345. include JavascriptGenerator
  2346. end
  2347. class EscapedEjavascript < Ejavascript
  2348. include EscapeEnhancer
  2349. end
  2350. #class XmlEjavascript < Ejavascript
  2351. # include EscapeEnhancer
  2352. #end
  2353. class PI::Ejavascript < PI::Engine
  2354. include JavascriptGenerator
  2355. def init_converter(properties={})
  2356. @pi = 'js'
  2357. super(properties)
  2358. end
  2359. end
  2360. end
  2361. #--end of require 'erubis/engine/ejavascript'
  2362. module Erubis
  2363. Ejs = Ejavascript
  2364. EscapedEjs = EscapedEjavascript
  2365. class CommandOptionError < ErubisError
  2366. end
  2367. ##
  2368. ## main class of command
  2369. ##
  2370. ## ex.
  2371. ## Main.main(ARGV)
  2372. ##
  2373. class Main
  2374. def self.main(argv=ARGV)
  2375. status = 0
  2376. begin
  2377. Main.new.execute(ARGV)
  2378. rescue CommandOptionError => ex
  2379. $stderr.puts ex.message
  2380. status = 1
  2381. end
  2382. exit(status)
  2383. end
  2384. def initialize
  2385. @single_options = "hvxztTSbeBXNUC"
  2386. @arg_options = "pcrfKIlaE" #C
  2387. @option_names = {
  2388. 'h' => :help,
  2389. 'v' => :version,
  2390. 'x' => :source,
  2391. 'z' => :syntax,
  2392. 'T' => :unexpand,
  2393. 't' => :untabify, # obsolete
  2394. 'S' => :intern,
  2395. 'b' => :bodyonly,
  2396. 'B' => :binding,
  2397. 'p' => :pattern,
  2398. 'c' => :context,
  2399. #'C' => :class,
  2400. 'e' => :escape,
  2401. 'r' => :requires,
  2402. 'f' => :datafiles,
  2403. 'K' => :kanji,
  2404. 'I' => :includes,
  2405. 'l' => :lang,
  2406. 'a' => :action,
  2407. 'E' => :enhancers,
  2408. 'X' => :notext,
  2409. 'N' => :linenum,
  2410. 'U' => :unique,
  2411. 'C' => :compact,
  2412. }
  2413. assert unless @single_options.length + @arg_options.length == @option_names.length
  2414. (@single_options + @arg_options).each_byte do |ch|
  2415. assert unless @option_names.key?(ch.chr)
  2416. end
  2417. end
  2418. def execute(argv=ARGV)
  2419. ## parse command-line options
  2420. options, properties = parse_argv(argv, @single_options, @arg_options)
  2421. filenames = argv
  2422. options['h'] = true if properties[:help]
  2423. opts = Object.new
  2424. arr = @option_names.collect {|ch, name| "def #{name}; @#{name}; end\n" }
  2425. opts.instance_eval arr.join
  2426. options.each do |ch, val|
  2427. name = @option_names[ch]
  2428. opts.instance_variable_set("@#{name}", val)
  2429. end
  2430. ## help, version, enhancer list
  2431. if opts.help || opts.version
  2432. puts version() if opts.version
  2433. puts usage() if opts.help
  2434. puts show_properties() if opts.help
  2435. puts show_enhancers() if opts.help
  2436. return
  2437. end
  2438. ## include path
  2439. opts.includes.split(/,/).each do |path|
  2440. $: << path
  2441. end if opts.includes
  2442. ## require library
  2443. opts.requires.split(/,/).each do |library|
  2444. require library
  2445. end if opts.requires
  2446. ## action
  2447. action = opts.action
  2448. action ||= 'syntax' if opts.syntax
  2449. action ||= 'convert' if opts.source || opts.notext
  2450. ## lang
  2451. lang = opts.lang || 'ruby'
  2452. action ||= 'convert' if opts.lang
  2453. ## class name of Eruby
  2454. #classname = opts.class
  2455. classname = nil
  2456. klass = get_classobj(classname, lang, properties[:pi])
  2457. ## kanji code
  2458. $KCODE = opts.kanji if opts.kanji
  2459. ## read context values from yaml file
  2460. datafiles = opts.datafiles
  2461. context = load_datafiles(datafiles, opts)
  2462. ## parse context data
  2463. if opts.context
  2464. context = parse_context_data(opts.context, opts)
  2465. end
  2466. ## properties for engine
  2467. properties[:escape] = true if opts.escape && !properties.key?(:escape)
  2468. properties[:pattern] = opts.pattern if opts.pattern
  2469. #properties[:trim] = false if opts.notrim
  2470. properties[:preamble] = properties[:postamble] = false if opts.bodyonly
  2471. properties[:pi] = nil if properties[:pi] == true
  2472. ## create engine and extend enhancers
  2473. engine = klass.new(nil, properties)
  2474. enhancers = get_enhancers(opts.enhancers)
  2475. #enhancers.push(Erubis::EscapeEnhancer) if opts.escape
  2476. enhancers.each do |enhancer|
  2477. engine.extend(enhancer)
  2478. engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
  2479. end
  2480. ## no-text
  2481. engine.extend(Erubis::NoTextEnhancer) if opts.notext
  2482. ## convert and execute
  2483. val = nil
  2484. msg = "Syntax OK\n"
  2485. if filenames && !filenames.empty?
  2486. filenames.each do |filename|
  2487. File.file?(filename) or
  2488. raise CommandOptionError.new("#{filename}: file not found.")
  2489. engine.filename = filename
  2490. engine.convert!(File.read(filename))
  2491. val = do_action(action, engine, context, filename, opts)
  2492. msg = nil if val
  2493. end
  2494. else
  2495. engine.filename = filename = '(stdin)'
  2496. engine.convert!($stdin.read())
  2497. val = do_action(action, engine, context, filename, opts)
  2498. msg = nil if val
  2499. end
  2500. print msg if action == 'syntax' && msg
  2501. end
  2502. private
  2503. def do_action(action, engine, context, filename, opts)
  2504. case action
  2505. when 'convert'
  2506. s = manipulate_src(engine.src, opts)
  2507. when nil, 'exec', 'execute'
  2508. s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
  2509. when 'syntax'
  2510. s = check_syntax(filename, engine.src)
  2511. else
  2512. raise "*** internal error"
  2513. end
  2514. print s if s
  2515. return s
  2516. end
  2517. def manipulate_src(source, opts)
  2518. flag_linenum = opts.linenum
  2519. flag_unique = opts.unique
  2520. flag_compact = opts.compact
  2521. if flag_linenum
  2522. n = 0
  2523. source.gsub!(/^/) { n += 1; "%5d: " % n }
  2524. source.gsub!(/^ *\d+:\s+?\n/, '') if flag_compact
  2525. source.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
  2526. else
  2527. source.gsub!(/^\s*?\n/, '') if flag_compact
  2528. source.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
  2529. end
  2530. return source
  2531. end
  2532. def usage(command=nil)
  2533. command ||= File.basename($0)
  2534. buf = []
  2535. buf << "erubis - embedded program converter for multi-language"
  2536. buf << "Usage: #{command} [..options..] [file ...]"
  2537. buf << " -h, --help : help"
  2538. buf << " -v : version"
  2539. buf << " -x : show converted code"
  2540. buf << " -X : show converted code, only ruby code and no text part"
  2541. buf << " -N : numbering: add line numbers (for '-x/-X')"
  2542. buf << " -U : unique: compress empty lines to a line (for '-x/-X')"
  2543. buf << " -C : compact: remove empty lines (for '-x/-X')"
  2544. buf << " -b : body only: no preamble nor postamble (for '-x/-X')"
  2545. buf << " -z : syntax checking"
  2546. buf << " -e : escape (equal to '--E Escape')"
  2547. buf << " -p pattern : embedded pattern (default '<% %>')"
  2548. buf << " -l lang : convert but no execute (ruby/php/c/cpp/java/scheme/perl/js)"
  2549. buf << " -E e1,e2,... : enhancer names (Escape, PercentLine, BiPattern, ...)"
  2550. buf << " -I path : library include path"
  2551. buf << " -K kanji : kanji code (euc/sjis/utf8) (default none)"
  2552. buf << " -c context : context data string (yaml inline style or ruby code)"
  2553. buf << " -f datafile : context data file ('*.yaml', '*.yml', or '*.rb')"
  2554. #buf << " -t : expand tab characters in YAML file"
  2555. buf << " -T : don't expand tab characters in YAML file"
  2556. buf << " -S : convert mapping key from string to symbol in YAML file"
  2557. buf << " -B : invoke 'result(binding)' instead of 'evaluate(context)'"
  2558. buf << " --pi=name : parse '<?name ... ?>' instead of '<% ... %>'"
  2559. #'
  2560. # -T : don't trim spaces around '<% %>'
  2561. # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
  2562. # -r library : require library
  2563. # -a : action (convert/execute)
  2564. return buf.join("\n")
  2565. end
  2566. def collect_supported_properties(erubis_klass)
  2567. list = []
  2568. erubis_klass.ancestors.each do |klass|
  2569. if klass.respond_to?(:supported_properties)
  2570. list.concat(klass.supported_properties)
  2571. end
  2572. end
  2573. return list
  2574. end
  2575. def show_properties
  2576. s = "supported properties:\n"
  2577. basic_props = collect_supported_properties(Erubis::Basic::Engine)
  2578. pi_props = collect_supported_properties(Erubis::PI::Engine)
  2579. list = []
  2580. common_props = basic_props & pi_props
  2581. list << ['(common)', common_props]
  2582. list << ['(basic)', basic_props - common_props]
  2583. list << ['(pi)', pi_props - common_props]
  2584. %w[ruby php c cpp java scheme perl javascript].each do |lang|
  2585. klass = Erubis.const_get("E#{lang}")
  2586. list << [lang, collect_supported_properties(klass) - basic_props]
  2587. end
  2588. list.each do |lang, props|
  2589. s << " * #{lang}\n"
  2590. props.each do |name, default_val, desc|
  2591. s << (" --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
  2592. end
  2593. end
  2594. s << "\n"
  2595. return s
  2596. end
  2597. def show_enhancers
  2598. dict = {}
  2599. ObjectSpace.each_object(Module) do |mod|
  2600. dict[$1] = mod if mod.name =~ /\AErubis::(.*)Enhancer\z/
  2601. end
  2602. s = "enhancers:\n"
  2603. dict.sort_by {|name, mod| name }.each do |name, mod|
  2604. s << (" %-13s : %s\n" % [name, mod.desc])
  2605. end
  2606. return s
  2607. end
  2608. def version
  2609. return Erubis::VERSION
  2610. end
  2611. def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
  2612. options = {}
  2613. context = {}
  2614. while argv[0] && argv[0][0] == ?-
  2615. optstr = argv.shift
  2616. optstr = optstr[1, optstr.length-1]
  2617. #
  2618. if optstr[0] == ?- # context
  2619. optstr =~ /\A\-([-\w]+)(?:=(.*))?/ or
  2620. raise CommandOptionError.new("-#{optstr}: invalid context value.")
  2621. name, value = $1, $2
  2622. name = name.gsub(/-/, '_').intern
  2623. #value = value.nil? ? true : YAML.load(value) # error, why?
  2624. value = value.nil? ? true : YAML.load("---\n#{value}\n")
  2625. context[name] = value
  2626. #
  2627. else # options
  2628. while optstr && !optstr.empty?
  2629. optchar = optstr[0].chr
  2630. optstr = optstr[1..-1]
  2631. if arg_none.include?(optchar)
  2632. options[optchar] = true
  2633. elsif arg_required.include?(optchar)
  2634. arg = optstr.empty? ? argv.shift : optstr or
  2635. raise CommandOptionError.new("-#{optchar}: #{@option_names[optchar]} required.")
  2636. options[optchar] = arg
  2637. optstr = nil
  2638. elsif arg_optional.include?(optchar)
  2639. arg = optstr.empty? ? true : optstr
  2640. options[optchar] = arg
  2641. optstr = nil
  2642. else
  2643. raise CommandOptionError.new("-#{optchar}: unknown option.")
  2644. end
  2645. end
  2646. end
  2647. #
  2648. end # end of while
  2649. return options, context
  2650. end
  2651. def untabify(str, width=8)
  2652. list = str.split(/\t/)
  2653. last = list.pop
  2654. sb = ''
  2655. list.each do |s|
  2656. column = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
  2657. n = width - (column % width)
  2658. sb << s << (' ' * n)
  2659. end
  2660. sb << last
  2661. return sb
  2662. end
  2663. #--
  2664. #def untabify(str, width=8)
  2665. # sb = ''
  2666. # str.scan(/(.*?)\t/m) do |s, |
  2667. # len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
  2668. # sb << s << (" " * (width - len % width))
  2669. # end
  2670. # return $' ? (sb << $') : str
  2671. #end
  2672. #++
  2673. def get_classobj(classname, lang, pi)
  2674. classname ||= "E#{lang}"
  2675. base_module = pi ? Erubis::PI : Erubis
  2676. begin
  2677. klass = base_module.const_get(classname)
  2678. rescue NameError
  2679. klass = nil
  2680. end
  2681. unless klass
  2682. if lang
  2683. msg = "-l #{lang}: invalid language name (class #{base_module.name}::#{classname} not found)."
  2684. else
  2685. msg = "-c #{classname}: invalid class name."
  2686. end
  2687. raise CommandOptionError.new(msg)
  2688. end
  2689. return klass
  2690. end
  2691. def get_enhancers(enhancer_names)
  2692. return [] unless enhancer_names
  2693. enhancers = []
  2694. shortname = nil
  2695. begin
  2696. enhancer_names.split(/,/).each do |name|
  2697. shortname = name
  2698. enhancers << Erubis.const_get("#{shortname}Enhancer")
  2699. end
  2700. rescue NameError
  2701. raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-h' to show all enhancers).")
  2702. end
  2703. return enhancers
  2704. end
  2705. def load_datafiles(filenames, opts)
  2706. context = Erubis::Context.new
  2707. return context unless filenames
  2708. filenames.split(/,/).each do |filename|
  2709. filename.strip!
  2710. test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
  2711. if filename =~ /\.ya?ml$/
  2712. if opts.unexpand
  2713. ydoc = YAML.load_file(filename)
  2714. else
  2715. ydoc = YAML.load(untabify(File.read(filename)))
  2716. end
  2717. ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
  2718. intern_hash_keys(ydoc) if opts.intern
  2719. context.update(ydoc)
  2720. elsif filename =~ /\.rb$/
  2721. str = File.read(filename)
  2722. context2 = Erubis::Context.new
  2723. _instance_eval(context2, str)
  2724. context.update(context2)
  2725. else
  2726. CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
  2727. end
  2728. end
  2729. return context
  2730. end
  2731. def _instance_eval(_context, _str)
  2732. _context.instance_eval(_str)
  2733. end
  2734. def parse_context_data(context_str, opts)
  2735. if context_str[0] == ?{
  2736. require 'yaml'
  2737. ydoc = YAML.load(context_str)
  2738. unless ydoc.is_a?(Hash)
  2739. raise CommandOptionError.new("-c: root object is not a mapping.")
  2740. end
  2741. intern_hash_keys(ydoc) if opts.intern
  2742. return ydoc
  2743. else
  2744. context = Erubis::Context.new
  2745. context.instance_eval(context_str, '-c')
  2746. return context
  2747. end
  2748. end
  2749. def intern_hash_keys(obj, done={})
  2750. return if done.key?(obj.__id__)
  2751. case obj
  2752. when Hash
  2753. done[obj.__id__] = obj
  2754. obj.keys.each do |key|
  2755. obj[key.intern] = obj.delete(key) if key.is_a?(String)
  2756. end
  2757. obj.values.each do |val|
  2758. intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
  2759. end
  2760. when Array
  2761. done[obj.__id__] = obj
  2762. obj.each do |val|
  2763. intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
  2764. end
  2765. end
  2766. end
  2767. def check_syntax(filename, src)
  2768. require 'open3'
  2769. #command = (ENV['_'] || 'ruby') + ' -wc' # ENV['_'] stores command name
  2770. bin = ENV['_'] && File.basename(ENV['_']) =~ /^ruby/ ? ENV['_'] : 'ruby'
  2771. command = bin + ' -wc'
  2772. stdin, stdout, stderr = Open3.popen3(command)
  2773. stdin.write(src)
  2774. stdin.close
  2775. result = stdout.read()
  2776. stdout.close()
  2777. errmsg = stderr.read()
  2778. stderr.close()
  2779. return nil unless errmsg && !errmsg.empty?
  2780. errmsg =~ /\A-:(\d+): /
  2781. linenum, message = $1, $'
  2782. return "#{filename}:#{linenum}: #{message}"
  2783. end
  2784. if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
  2785. def check_syntax(filename, src)
  2786. require 'compiler'
  2787. verbose = $VERBOSE
  2788. msg = nil
  2789. begin
  2790. $VERBOSE = true
  2791. Rubinius::Compiler.compile_string(src, filename)
  2792. rescue SyntaxError => ex
  2793. ex_linenum = ex.line
  2794. linenum = 0
  2795. srcline = src.each_line do |line|
  2796. linenum += 1
  2797. break line if linenum == ex_linenum
  2798. end
  2799. msg = "#{ex.message}\n"
  2800. msg << srcline
  2801. msg << "\n" unless srcline =~ /\n\z/
  2802. msg << (" " * (ex.column-1)) << "^\n"
  2803. ensure
  2804. $VERBOSE = verbose
  2805. end
  2806. return msg
  2807. end
  2808. end
  2809. end
  2810. end
  2811. #--end of require 'erubis/main'
  2812. Erubis::Main.main(ARGV)