merb-assets-1.1.3/0000755000175000017500000000000011755425071013254 5ustar tfheentfheenmerb-assets-1.1.3/Rakefile0000644000175000017500000000136311755425071014724 0ustar tfheentfheenrequire 'rubygems' require 'rake' # Load this library's version information require File.expand_path('../lib/merb-assets/version', __FILE__) require 'spec/rake/spectask' Spec::Rake::SpecTask.new(:spec) do |spec| spec.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts') spec.libs << 'lib' << 'spec' spec.spec_files = FileList['spec/**/*_spec.rb'] end Spec::Rake::SpecTask.new(:rcov) do |spec| spec.libs << 'lib' << 'spec' spec.pattern = 'spec/**/*_spec.rb' spec.rcov = true end task :default => :spec require 'rake/rdoctask' Rake::RDocTask.new do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = "test_gem #{Merb::Assets::VERSION}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('lib/**/*.rb') end merb-assets-1.1.3/spec/0000755000175000017500000000000011755425071014206 5ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/0000755000175000017500000000000011755425071016057 5ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/javascripts/0000755000175000017500000000000011755425071020410 5ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/javascripts/jquery.js0000644000175000017500000000000011755425071022253 0ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/stylesheets/0000755000175000017500000000000011755425071020433 5ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/stylesheets/style.css0000644000175000017500000000000011755425071022273 0ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/images/0000755000175000017500000000000011755425071017324 5ustar tfheentfheenmerb-assets-1.1.3/spec/fixtures/images/merb.jpg0000644000175000017500000011632611755425071020764 0ustar tfheentfheenJFIFHH ExifMM*bj(1r2i ' 'Adobe Photoshop CS2 Macintosh2007:08:31 12:39:35ȠW&(. hHHJFIFHH Adobe_CMAdobed            F" ?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?TI%)$IJI$RI$I%)$IJI$RU:CMN,..0ӕ 5,+J,&8d&/zJI$T.c=,p-4~{`}'=J5Ǘ `eq2OXӊjk˭s6.q*[ၔ/GJz5mƵ/{K~slα~CkT4#7o\w^_>/Wzd /sLi ୎{57V5j'7?aŜr?*zϫxٓsX 'UE8UZ+m$ 'wJ'7HM$ڟ#*|ɑn:cls$$`%XѪ Ln8K$"U80HHϺ\É<L~jަkH-$\}`o\ŧ"DåT,HKs@L'7.askX[t=7X9.}v5cyRr4s ΍ J 䑗S'SQnֹp;|^nybj>QӺmɱ cg)t zFQɬzήW\-:?s滯zEwu Qr|rgOn# =_;ᜡ굤4i,O]v\Nރys?[?qÎ<1s Po}K6^4zv j@[IGsm4m2X^|w9OX;.+BX\즽^\epg'2\Yj[wRsz87 jZ!),Vk[>Y<LW_Ǣևcmkx m?e[Suo#U,}.Z˪O#k?_Y}LAz1['bO eL CȏvګtҮ7a+vx+h{?I.e'ǓSw1;'!8ˋt׆q|ʼO1:Z(cdTg֌̾zVTk7~eU~ ;"?ҸݭZt^ :{hmXրײ@;s}ۙ |Q"yns]㛺PP7>Tǹ*gS{}z+:LoMoKu"6ND9d]ag"'I2\0!`Csu[,D# c:n_Wn&00Los߸bcUHU- ` Xx0m`|]³$3̓ Tʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$6Photoshop 3.08BIM8BIM%F &Vڰw8BIM com.apple.print.PageFormat.PMHorizontalRes com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMHorizontalRes 72 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMOrientation com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMOrientation 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMScaling com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMScaling 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMVerticalRes com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMVerticalRes 72 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMVerticalScaling com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMVerticalScaling 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.subTicket.paper_info_ticket com.apple.print.PageFormat.PMAdjustedPageRect com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMAdjustedPageRect 0.0 0.0 734 576 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-08-31T18:35:59Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMAdjustedPaperRect com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMAdjustedPaperRect -18 -18 774 594 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-08-31T18:35:59Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.PMPaperName com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMPaperName na-letter com.apple.print.ticket.client com.apple.print.pm.PostScript com.apple.print.ticket.modDate 2003-07-01T17:49:36Z com.apple.print.ticket.stateFlag 1 com.apple.print.PaperInfo.PMUnadjustedPageRect com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMUnadjustedPageRect 0.0 0.0 734 576 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.PMUnadjustedPaperRect com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMUnadjustedPaperRect -18 -18 774 594 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2007-05-12T04:00:36Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.ppd.PMPaperName com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.ppd.PMPaperName US Letter com.apple.print.ticket.client com.apple.print.pm.PostScript com.apple.print.ticket.modDate 2003-07-01T17:49:36Z com.apple.print.ticket.stateFlag 1 com.apple.print.ticket.APIVersion 00.20 com.apple.print.ticket.privateLock com.apple.print.ticket.type com.apple.print.PaperInfoTicket com.apple.print.ticket.APIVersion 00.20 com.apple.print.ticket.privateLock com.apple.print.ticket.type com.apple.print.PageFormatTicket 8BIMxHH@Rg(HH(dh 8BIMHH8BIM&?8BIM x8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIMnullbaseNameTEXTUserboundsObjcRct1Top longLeftlongBtomlongWRghtlongslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongWRghtlongurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM 8BIM F@ hJFIFHH Adobe_CMAdobed            F" ?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?TI%)$IJI$RI$I%)$IJI$RU:CMN,..0ӕ 5,+J,&8d&/zJI$T.c=,p-4~{`}'=J5Ǘ `eq2OXӊjk˭s6.q*[ၔ/GJz5mƵ/{K~slα~CkT4#7o\w^_>/Wzd /sLi ୎{57V5j'7?aŜr?*zϫxٓsX 'UE8UZ+m$ 'wJ'7HM$ڟ#*|ɑn:cls$$`%XѪ Ln8K$"U80HHϺ\É<L~jަkH-$\}`o\ŧ"DåT,HKs@L'7.askX[t=7X9.}v5cyRr4s ΍ J 䑗S'SQnֹp;|^nybj>QӺmɱ cg)t zFQɬzήW\-:?s滯zEwu Qr|rgOn# =_;ᜡ굤4i,O]v\Nރys?[?qÎ<1s Po}K6^4zv j@[IGsm4m2X^|w9OX;.+BX\즽^\epg'2\Yj[wRsz87 jZ!),Vk[>Y<LW_Ǣևcmkx m?e[Suo#U,}.Z˪O#k?_Y}LAz1['bO eL CȏvګtҮ7a+vx+h{?I.e'ǓSw1;'!8ˋt׆q|ʼO1:Z(cdTg֌̾zVTk7~eU~ ;"?ҸݭZt^ :{hmXրײ@;s}ۙ |Q"yns]㛺PP7>Tǹ*gS{}z+:LoMoKu"6ND9d]ag"'I2\0!`Csu[,D# c:n_Wn&00Los߸bcUHU- ` Xx0m`|]³$3̓ Tʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$8BIM!UAdobe PhotoshopAdobe Photoshop CS28BIMmoptHTargetSettingsMttCObjc NativeQuadBl longGrn longRd longTrnsbool addMetadatabool fileFormatenum FileFormatPNG24 interlacedbool noMatteColorbooltransparencyDitherAlgorithmenumDitherAlgorithmNonetransparencyDitherAmountlong8BIM-msetnullVersionlong8BIMms4w8BIMmaniIRFR8BIMAnDsnullAFStlongFrInVlLsObjcnullFrIDlong$LFStsVlLsObjcnullFsIDlongAFrmlongFsFrVlLslong$LLCntlong8BIMRoll8BIMmfri8BIM:http://ns.adobe.com/xap/1.0/ image/jpeg Adobe Photoshop CS2 Macintosh 2007-08-31T12:39:34-06:00 2007-08-31T12:39:35-06:00 2007-08-31T12:39:35-06:00 uuid:EF38B731595011DC8A32BD4CFFC80273 uuid:EF38B732595011DC8A32BD4CFFC80273 uuid:63EAD7545D59DC119843CA11B581893E uuid:DE7909F0AD01DC11B4F6C63E94062379 1 720000/10000 720000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;2616AC826EA923373212B2CAF924E20A 200 87 1 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;61D8F885439D40E9F13E5F64DCBA214E 3 sRGB IEC61966-2.1 XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmAdobed         W!1AQaq"2BRsTb#S5c$U !1Q"2BR3AbrqSsa#$C4 ?( @ @ @( @ @ϓ6Hcd./)M.VS#U]h [W1vE1hޕi嚵KŪ@( @ @nӜ"\KbOcwj'I.5j7?}ik= sZROXm%Vb?o}ډk_MAڳOׇqd8_#.syI^򒊫tD7?s`Z8zZT%eHo#cxmgdOZuVR${8XY%zWˤF槗]9x !a:\|*Vu #8eM1rH .Wi7GZv;|$t`I{o 2^Z3]̙иIzO#b;tqmYׇ>ypE,{\M:Rfԝ#( #*I/rv!vū>@*V3VUg% 9$fơ^P\/z(<ԹLnkE"a]!+W>_s{gMwxZ<^r%8˚ |]^y㤟&%K/q3B9/_s'Wg.p28 ؏Lh{I*PTavcpd >Gw+̪!с*;Z`d<+ Zy%(<2C9&2V }#`>T5ZrQ"y&e:i0|7 '+p9lG+p!+е N.Ƕ e~SVs]J{hdoZڞ;JW#$lqG5$}[rt[[!QmgM̐-S\排[&b㰛RCLY-fC7c+y *6oJԱFXY D)mQ9Mn¦prss9&>2?w+$rv Hs9+|.e}#9dwyHmg/tʚLC{EܗS$5*yqOk1q|qϿ[AY1r sqv-2HW[P q[KZՕfR1WVMiݯ Z|5Lj^8"OTGavyHl/qc WKj6]OJx9/_s'Wg/!p27 X[%Z滤jRD褪Kvr .Y4|rߴ557Jܡb7k7Wf>^.1$~d`rG%(c{d-cuRJhӊWcɎ#Ӗ9hۼ]oۉwy4P)!sN- C(W̮[JNfʌRX&@Ӥ,$ipH3|Q݌g]= eKT݌dຶlEh^*"}K?o͗8dsra{7[$Np:9^ Ҵ<'F4εWvy, 1qJ˜'W1euǑKye]-%vɚ@'wҺZ7JܺKH(Pϓ\o<7 |F{DO4#x_{o%$M5}+zvc}b3|8y^,QL9/_s'Wg/!p3=wrE q#l++>&c-_A7;pngkph13.;WKԩ"&vҵNhmJE+4uZaoguwiwN|2 o^#5eJfwқ;M81\ٵN֗"38G^,rLT X^TѠЍJ7g:Wƹ噬κI{=+O)/o^$we~ -h[4WIO+W#YI;1 f9 ^5!h]ʽfn29/_s'Wg/!p33pMq>Uƨ4.GF^(uӰpμ$ʼn}w@gѼoԸZ5\¼=k_~ ;VƁ3KSf&#ݝ_v|zϙK]=xwlͽr !ka'7[9u:1O$mJRQubO[0stCLK VHZDy Вg̦Ȍ(3jwSÆqԗ'zd+~N裝8QNese7#2*/FvEzևO^tA/ʯiqfbẼCݔOV=v\v,F$Uk0E>w@\8\h[0{7z}_gllK/vn+< !q ac4[C6Zo6\Plʳ߾i֑UuάUem/FO.t1NRIe~żmSHW[B*'EPCLeC«KF\ Ǘ^Mq!x{NˉRUg-&0㋘Ih(ܥ Z5}Lhw[Z .?S-GU3_ҾWxZ8]&KfAJVPK[Y陋M+9ݥhouvҠu[62xĿY{]0>%=5rgܵ4cqEe9MàYKo#yu4y:>LNa\Zz .)x6Yk-渑ܚZ(+a%Km=ٹ)m2%STNv.F8e:s8$ n">Tj[K QioqlmɃtųI! Rs.\T=(yQvʹ[S8eDyYHP˪u.MN_)rl}hƓuzB4/ ddL-~]=C?de2Xx^?c^1­p!j?OSuHn} 0 8Au"7qė8e̦Y$§w'j(2. OyR&7q[Z[أtVmYH(IpͭF+đ kj7$ D𿃋Ы|R$wq:[v򉠶dr^B*(-ATY#՝}Mpf&#)o?+}m\Bl/y|<+Zx&鵁\iRQ=R=E\F%"NTČqzoXD6kJjmEaDKoMXEr֯Ui.KDzBvc.+c,Zn*$J @( @ @ @merb-assets-1.1.3/spec/spec_helper.rb0000644000175000017500000000123311755425071017023 0ustar tfheentfheenrequire "rubygems" require "json" # Use current merb-core sources if running from a typical dev checkout. lib = File.expand_path('../../../merb-core/lib', __FILE__) $LOAD_PATH.unshift(lib) if File.directory?(lib) require 'merb-core' # The lib under test require "merb-assets" # Satisfies Autotest and anyone else not using the Rake tasks require 'spec' Merb.start :environment => 'test' Merb::Plugins.config[:asset_helpers][:max_hosts] = 4 Merb::Plugins.config[:asset_helpers][:asset_domain] = "assets%d" Merb::Plugins.config[:asset_helpers][:domain] = "my-awesome-domain.com" Spec::Runner.configure do |config| config.include Merb::Test::RequestHelper end merb-assets-1.1.3/spec/spec.opts0000644000175000017500000000003211755425071016042 0ustar tfheentfheen--format specdoc --colour merb-assets-1.1.3/spec/merb-assets_spec.rb0000644000175000017500000005032411755425071017776 0ustar tfheentfheenrequire 'spec_helper' Merb.push_path(:public, 'spec/fixtures/') include Merb::AssetsMixin describe "Accessing Assets" do it "should create link to name with absolute url" do link_to("The Merb home page", "http://www.merbivore.com/").should == "The Merb home page" end it "should create link to name with relative url" do link_to("The Entry Title", "/blog/show/13").should == "The Entry Title" end it "should create link with attributes" do link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'}).should match(%r{class="special"}) link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'}).should match(%r{target="blank"}) end it "should create link with explicit href" do link_to("The Foo home page", "http://not.foo.example.com/", :href => "http://foo.example.com").should == "The Foo home page" end it "should create image tag with absolute url" do image_tag('http://example.com/foo.gif').should == "" end it "should create image tag with relative url" do image_tag('foo.gif').should == "" end it "should create image tag with class" do result = image_tag('foo.gif', :class => 'bar') result.should match(%r{}) result.should match(%r{src="/images/foo.gif"}) result.should match(/class="bar"/) end it "should create image tag with specified path" do image_tag('foo.gif', :path => '/files/').should == "" end it "should create image tag without extension" do image_tag('/dynamic/charts').should == "" end it "should create image tag without extension and with specified path" do image_tag('charts', :path => '/dynamic/').should == "" end it "should create image tag with a random query string" do result = image_tag('foo.gif', :reload => true) result.should match(%r{}) end it "should not create image tag with nil image" do image_tag(nil).should == "" end it "should not create image tag with empty string" do image_tag('').should == "" end end describe "With Merb::Config[:path_prefix] set," do before(:all) do Merb::Config[:path_prefix] = "/myapp" end after(:all) do Merb::Config[:path_prefix] = nil end describe "create an image tag" do it "with a relative url" do image_tag('foo.gif').should == "" end it "with an absolute url" do image_tag('/foo.gif').should == "" end it "with an external url" do image_tag('http://example.com/foo.gif').should == "" end end describe "create a stylesheet include tag" do it "with a relative url" do result = css_include_tag('bar.css') result.should match(%r{^$}) result.should match(%r{type="text/javascript"}) result.should match(%r{src="/myapp/javascripts/bar.js"}) result.should match(%r{charset="utf-8"}) end it "with an absolute url" do result = js_include_tag("/bar.js") result.should match(%r{^$}) result.should match(%r{type="text/javascript"}) result.should match(%r{src="/myapp/bar.js"}) end it "with an external url" do result = js_include_tag("http://example.com/bar.js") result.should match(%r{^$}) result.should match(%r{type="text/javascript"}) result.should match(%r{src="http://example.com/bar.js"}) end it "with a specific charset option" do result = js_include_tag("bar.js", :charset => 'iso-8859-1') result.should match(%r{^$}) result.should match(%r{type="text/javascript"}) result.should match(%r{src="/myapp/javascripts/bar.js"}) result.should match(%r{charset="iso-8859-1"}) end end end describe "With Merb::Config[:reload_templates] set," do before(:all) do Merb::Config[:reload_templates] = true end after(:all) do Merb::Config[:reload_templates] = false end it "should create image tag with absolute url" do image_tag('http://example.com/foo.gif').should == "" end it "should create image tag with absolute url and random string if :reload option is set" do image_tag('http://example.com/foo.gif', :reload => true).should =~ %r{} end it "should create image tag with relative url" do image_tag('foo.gif').should =~ %r{} end end describe "With Merb::Plugins.config[:asset_helpers][:asset_timestamp] set," do before(:all) do Merb::Plugins.config[:asset_helpers][:asset_timestamp] = true end after(:all) do Merb::Plugins.config[:asset_helpers][:asset_timestamp] = false end it "should create image tag with absolute url" do image_tag('http://example.com/foo.gif').should == "" end it "should not add timestamp to the image tag with absolute url if :timestamp option is set" do image_tag('http://example.com/foo.gif', :timestamp => true).should =~ %r{} end it "should create image tag with relative url" do image_tag('merb.jpg').should =~ %r{} end it "should create image tag with relative url and timestamp which is provided" do image_tag('merb.jpg', :timestamp => 123456789).should =~ %r{} end end describe "JavaScript related functions" do it "should escape js having quotes" do escape_js("'Lorem ipsum!' -- Some guy").should == "\\'Lorem ipsum!\\' -- Some guy" end it "should escape js having new lines" do escape_js("Please keep text\nlines as skinny\nas possible.").should == "Please keep text\\nlines as skinny\\nas possible." end it "should convert objects that respond to to_json to json" do expected = {'user' => 'Lewis', 'page' => 'home'} JSON.parse(js(expected)).should == expected end it "should convert objects using inspect that don't respond to_json to json" do js([ 1, 2, {"a"=>3.141}, false, true, nil, 4..10 ]).should == "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]" end end describe "External JavaScript and Stylesheets" do it "should require a js file only once" do require_js :jquery require_js :jquery, :effects include_required_js.scan(%r{src="/javascripts/jquery.js"}).should have(1).things include_required_js.scan(%r{src="/javascripts/effects.js"}).should have(1).things end it "should require a css file only once" do require_css :style require_css :style, 'ie-specific' include_required_css.scan(%r{href="/stylesheets/style.css"}).should have(1).things include_required_css.scan(%r{href="/stylesheets/ie-specific.css"}).should have(1).things end it "should require included js" do require_js 'jquery', 'effects', 'validation' result = include_required_js result.scan(/ uniq_js_path("my") #=> "http://assets2.my-awesome-domain.com/javascripts/my.js" uniq_js_path(["admin/secrets","home/signup"]) #=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js", "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"] re_js and require_css, include_required_js and include_requried_css quire assets in parts/partials just once: In your application layout: js_include_tag :prototype, :lowpro, :bundle => :base In your controller layout: require_js :bundle => :posts The require_js method can be used to require any JavaScript file anywhere in your templates. Regardless of how many times a single script is included with require_js, Merb will only include it once in the header. # File: app/views/layouts/application.html.erb <%= include_required_js %> <%= include_required_css %> <%= catch_content :layout %> # File: app/views/whatever/_part1.herb <% require_js 'this' -%> <% require_css 'that', 'another_one' -%> # File: app/views/whatever/_part2.herb <% require_js 'this', 'something_else' -%> <% require_css 'that' -%> # File: app/views/whatever/index.herb <%= partial(:part1) %> <%= partial(:part2) %> # Will generate the following in the final page... . . . # my_action.herb has a call to require_css 'style' # File: layout/application.html.erb include_required_css # => # my_action.herb has a call to require_css 'style', 'ie-specific' # File: layout/application.html.erb include_required_css # => # # my_action.herb has a call to require_js 'jquery' # File: layout/application.html.erb include_required_js # => # my_action.herb has a call to require_js 'jquery', 'effects', 'validation' # File: layout/application.html.erb include_required_js # => # # <% require_css('style') %> # A subsequent call to include_required_css will render... # => <% require_css('style', 'ie-specific') %> # A subsequent call to include_required_css will render... # => # <% require_js 'jquery' %> # A subsequent call to include_required_js will render... # => <% require_js 'jquery', 'effects' %> # A subsequent call to include_required_js will render... # => # css_include_tag and js_include_tag that do not use asset subdomains: css_include_tag 'style' # => css_include_tag 'style.css', 'layout' # => # css_include_tag :menu # => css_include_tag :style, :screen # => # css_include_tag :style, :media => :print # => css_include_tag :style, :charset => 'iso-8859-1' # => js_include_tag 'jquery' # => js_include_tag 'moofx.js', 'upload' # => # js_include_tag :effects # => js_include_tag :jquery, :validation # => # Utility methods examples ========================== uniq_css_path("my") #=> "http://assets2.my-awesome-domain.com/stylesheets/my.css" uniq_css_path(["admin/secrets","home/signup"]) #=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css", "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"] uniq_path("/javascripts/my.js","/javascripts/my.css") #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/javascripts/my.css"] uniq_path(["/javascripts/my.js","/stylesheets/my.css"]) #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"] uniq_path(%w(/javascripts/my.js /stylesheets/my.css)) #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"] uniq_path('/stylesheets/somearbitrary.css') #=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css" uniq_path('/images/hostsexypicture.jpg') #=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg"merb-assets-1.1.3/metadata.yml0000644000175000017500000000422711755425071015564 0ustar tfheentfheen--- !ruby/object:Gem::Specification name: merb-assets version: !ruby/object:Gem::Version hash: 21 prerelease: false segments: - 1 - 1 - 3 version: 1.1.3 platform: ruby authors: - Ezra Zygmuntowicz autorequire: bindir: bin cert_chain: [] date: 2010-07-11 00:00:00 +01:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: merb-core prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version hash: 21 segments: - 1 - 1 - 3 version: 1.1.3 type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: rspec prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 13 segments: - 1 - 2 - 9 version: 1.2.9 type: :development version_requirements: *id002 description: Merb plugin for supporting assets email: ez@engineyard.com executables: [] extensions: [] extra_rdoc_files: - README - LICENSE - TODO files: - Rakefile - lib/merb-assets/assets_mixin.rb - lib/merb-assets/assets.rb - lib/merb-assets/version.rb - lib/merb-assets.rb - spec/fixtures/images/merb.jpg - spec/fixtures/javascripts/jquery.js - spec/fixtures/stylesheets/style.css - spec/spec.opts - spec/spec_helper.rb - spec/merb-assets_spec.rb - README - LICENSE - TODO has_rdoc: true homepage: http://merbivore.com/ licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.3.7 signing_key: specification_version: 3 summary: Merb plugin that provides helpers for assets and asset bundling test_files: [] merb-assets-1.1.3/TODO0000644000175000017500000000024611755425071013746 0ustar tfheentfheenTODO: Fix LICENSE with your name Fix Rakefile with your name and contact info Add your code to lib/merb-haml.rb Add your Merb rake tasks to lib/merb-haml/merbtasks.rbmerb-assets-1.1.3/LICENSE0000644000175000017500000000204411755425071014261 0ustar tfheentfheenCopyright (c) 2008 Ezra Zygmuntowicz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.merb-assets-1.1.3/lib/0000755000175000017500000000000011755425071014022 5ustar tfheentfheenmerb-assets-1.1.3/lib/merb-assets/0000755000175000017500000000000011755425071016247 5ustar tfheentfheenmerb-assets-1.1.3/lib/merb-assets/version.rb0000644000175000017500000000010311755425071020253 0ustar tfheentfheenmodule Merb module Assets VERSION = '1.1.3'.freeze end end merb-assets-1.1.3/lib/merb-assets/assets.rb0000644000175000017500000001776411755425071020115 0ustar tfheentfheenmodule Merb module Assets # Check whether the assets should be bundled. # # ==== Returns # Boolean:: # True if the assets should be bundled (e.g., production mode or # :bundle_assets is explicitly enabled). def self.bundle? (Merb.environment == 'production') || (!!Merb::Config[:bundle_assets]) end # Helpers for handling asset files. module AssetHelpers ASSET_FILE_EXTENSIONS = { :javascript => ".js", :stylesheet => ".css" } # Returns the URI path to a particular asset file. If +local_path+ is # true, returns the path relative to the Merb.root, not the public # directory. Uses the path_prefix, if any is configured. # # ==== Parameters # asset_type:: Type of the asset (e.g. :javascript). # filename<~to_s>:: The path to the file. # local_path:: # If true, the returned path will be relative to the Merb.root, # otherwise it will be the public URI path. Defaults to false. # # ==== Returns # String:: The path to the asset. # # ==== Examples # asset_path(:javascript, :dingo) # # => "/javascripts/dingo.js" # # asset_path(:javascript, :dingo, true) # # => "public/javascripts/dingo.js" def asset_path(asset_type, filename, local_path = false) filename = filename.to_s return filename if filename =~ %r{^https?://} #leave absolte paths alone # add extension if none given if filename !~ /#{'\\' + ASSET_FILE_EXTENSIONS[asset_type]}\Z/ && filename.index('?').nil? filename = "#{filename}#{ASSET_FILE_EXTENSIONS[asset_type]}" # don't modify receiver end # prepend asset type's folder path filename = "/#{asset_type}s/#{filename}" unless filename.index("/") == 0 if local_path return "public#{filename}" else return "#{Merb::Config[:path_prefix]}#{filename}" end end end # Helper for creating unique paths to a file name # Can increase speed for browsers that are limited to a certain number of connections per host # for downloading static files (css, js, images...) class UniqueAssetPath class << self # Builds the path to the file based on the name # # ==== Parameters # filename:: Name of file to generate path for # # ==== Returns # String:: The path to the asset. # # ==== Examples # build("/javascripts/my_fancy_script.js") # # => "https://assets5.my-awesome-domain.com/javascripts/my_fancy_script.js" # def build(filename) config = Merb::Plugins.config[:asset_helpers] #%{#{(USE_SSL ? 'https' : 'http')}://#{sprintf(config[:asset_domain],self.calculate_host_id(file))}.#{config[:domain]}/#{filename}} path = config[:use_ssl] ? 'https://' : 'http://' path << sprintf(config[:asset_domain],self.calculate_host_id(filename)) << "." if config[:asset_domain] path << config[:domain] path << "/" if filename.index('/') != 0 path << filename end protected # Calculates the id for the host def calculate_host_id(filename) ascii_total = 0 filename.each_byte {|byte| ascii_total += byte } (ascii_total % Merb::Plugins.config[:asset_helpers][:max_hosts] + 1) end end end # An abstract class for bundling text assets into single files. class AbstractAssetBundler class_inheritable_accessor :cached_bundles self.cached_bundles ||= [] class << self # Mark a bundle as cached. # # ==== Parameters # name<~to_s>:: Name of the bundle # def cache_bundle(name) cached_bundles.push(name.to_s) end # Purge a bundle from the cache. # # ==== Parameters # name<~to_s>:: Name of the bundle # def purge_bundle(name) cached_bundles.delete(name.to_s) end # Test if a bundle has been cached. # # ==== Parameters # name<~to_s>:: Name of the bundle # # ==== Returns # Boolean:: Whether the bundle has been cached or not. def cached_bundle?(name) cached_bundles.include?(name.to_s) end # ==== Parameters # &block:: A block to add as a post-bundle callback. # # ==== Examples # add_callback { |filename| `yuicompressor #{filename}` } def add_callback(&block) callbacks << block end alias_method :after_bundling, :add_callback # Retrieve existing callbacks. # # ==== Returns # Array[Proc]:: An array of existing callbacks. def callbacks @callbacks ||= [] return @callbacks end # The type of asset for which the bundler is responsible. Override # this method in your bundler code. # # ==== Raises # NotImplementedError:: This method is implemented by the bundler. # # ==== Returns # Symbol:: The type of the asset def asset_type raise NotImplementedError, "should return a symbol for the first argument to be passed to asset_path" end end # ==== Parameters # name<~to_s>:: # Name of the bundle. If name is true, it will be converted to :all. # *files:: Names of the files to bundle. def initialize(name, *files) @bundle_name = name == true ? :all : name @bundle_filename = Merb.root / asset_path(self.class.asset_type, @bundle_name, true) @files = files.map { |f| Merb.root / asset_path(self.class.asset_type, f, true) } end # Creates the new bundled file, executing all the callbacks. # # ==== Returns # Symbol:: Name of the bundle. def bundle! # TODO: push it out to the helper level so we don't have to create the helper object. unless self.class.cached_bundle?(@bundle_name) # skip regeneration of new bundled files - preventing multiple merb apps stepping on eachother # file needs to be older than 60 seconds to be regenerated if File.exist?(@bundle_filename) && File.mtime(@bundle_filename) >= Time.now - 60 return @bundle_name # serve the old file for now - to be regenerated later end bundle_files(@bundle_filename, *@files) if File.exist?(@bundle_filename) self.class.callbacks.each { |c| c.call(@bundle_filename) } Merb.logger.info("Assets: bundled :#{@bundle_name} into #{File.basename(@bundle_filename)}") self.class.cache_bundle(@bundle_name) end end return @bundle_name end protected include Merb::Assets::AssetHelpers # for asset_path # Bundle all the files into one. # # ==== Parameters # filename:: Name of the bundle file. # *files:: Filenames to be bundled. def bundle_files(filename, *files) File.open(filename, "w") do |f| f.flock(File::LOCK_EX) files.each { |file| f.puts(File.read(file)) } f.flock(File::LOCK_UN) end end end # Bundles javascripts into a single file: # # javascripts/#{name}.js class JavascriptAssetBundler < AbstractAssetBundler # ==== Returns # Symbol:: The asset type, i.e. :javascript. def self.asset_type :javascript end end # Bundles stylesheets into a single file: # # stylesheets/#{name}.css class StylesheetAssetBundler < AbstractAssetBundler # ==== Returns # Symbol:: The asset type, i.e. :stylesheet. def self.asset_type :stylesheet end end end end merb-assets-1.1.3/lib/merb-assets/assets_mixin.rb0000644000175000017500000007653511755425071021322 0ustar tfheentfheenmodule Merb # The AssetsMixin module provides a number of helper methods to views for # linking to assets and other pages, dealing with JavaScript and CSS. # # Merb provides views with convenience methods for links images and other # assets. module AssetsMixin include Merb::Assets::AssetHelpers ABSOLUTE_PATH_REGEXP = %r{^#{Merb::Const::HTTP}s?://} # This tests whether a random query string shall be appended to a url. # # Basically, you tell it your intention and if it's ok to use default # config values, and it will either use your intention or the value # set in Merb::Config[:reload_templates] # # @example # Merb::AssetsMixin.append_random_query_string?(options[:reload]) # Merb::AssetsMixin.append_random_query_string?(options[:reload], !absolute) # # @param [Boolean] intention: true if a random string shall be appended # @param [Boolean] allow_default: true if it's ok to use Merb::Config[:reload_templates] # @return [Boolean] true if a random query string shall be appended def self.append_random_query_string?(intention, allow_default = true) intention.nil? && allow_default ? Merb::Config[:reload_templates] : intention end # This tests whether a timestamp query string shall be appended to a url. # # @see self.append_random_query_string? # # @example # Merb::AssetsMixin.append_timestamp_query_string?(options[:timestamp]) # Merb::AssetsMixin.append_timestamp_query_string?(options[:timestamp], !absolute) # # @param [Boolean] intention: true if a timestamp string shall be appended # @param [Boolean] allow_default: true if it's ok to use Merb::Plugins.config[:asset_helpers][:asset_timestamp] # @return [Boolean] true if a timestamp query string shall be appended def self.append_timestamp_query_string?(intention, allow_default = true) intention.nil? && allow_default ? Merb::Plugins.config[:asset_helpers][:asset_timestamp] : intention end # Automatically generates link for CSS and JS # # We want all possible matches in the FileSys up to the action name # Given: controller_name = "namespace/controller" # action_name = "action" # @example # If all files are present should generate link/script tags for: # namespace.(css|js) # namespace/controller.(css|js) # namespace/controller/action.(css|js) # # @return [String] html def auto_link [auto_link_css, auto_link_js].join(Merb::Const::NEWLINE) end # We want all possible matches in the file system upto the action name # for CSS. The reason for separating auto_link for CSS and JS is # performance concerns with page loading. See Yahoo performance rules # (http://developer.yahoo.com/performance/rules.html) # # @return [String] html def auto_link_css auto_link_paths.map do |path| asset_exists?(:stylesheet, path) ? css_include_tag(path) : nil end.compact.join(Merb::Const::NEWLINE) end # ==== Parameters # none # # ==== Returns # html # # ==== Examples # We want all possible matches in the file system upto the action name # for JS. The reason for separating auto_link for CSS and JS is # performance concerns with page loading. See Yahoo performance rules # (http://developer.yahoo.com/performance/rules.html) def auto_link_js auto_link_paths.map do |path| asset_exists?(:javascript, path) ? js_include_tag(path) : nil end.compact.join(Merb::Const::NEWLINE) end # ==== Parameters # asset_type: A symbol representing the type of the asset. # asset_path: The path to the asset # # ==== Returns # exists? # # ==== Examples # This tests whether a give asset exists in the file system. def asset_exists?(asset_type, asset_path) File.exists?(Merb.root / asset_path(asset_type, asset_path, true)) end # ==== Parameters # none # # ==== Returns # paths # # ==== Examples # This is an auxiliary method which returns an array of all possible asset # paths for the current controller/action. def auto_link_paths paths = (controller_name / action_name).split(Merb::Const::SLASH) first = paths.shift paths.inject( [first] ) do |memo, val| memo.push [memo.last, val].join(Merb::Const::SLASH) end end # ==== Parameters # name<~to_s>:: The text of the link. # url<~to_s>:: The URL to link to. Defaults to an empty string. # opts:: Additional HTML options for the link. # # ==== Examples # link_to("The Merb home page", "http://www.merbivore.com/") # # => The Merb home page # # link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'}) # # => The Ruby home page # # link_to p.title, "/blog/show/#{p.id}" # # => The Entry Title # def link_to(name, url='', opts={}) opts[:href] ||= url %{#{name}} end # Generate IMG tag # # @param [String, #to_s] img The image path. # @param [Hash] opts Additional options for the image tag (see below). # @option opts [String] :path # Sets the path prefix for the image. Defaults to "/images/" or whatever # is specified in Merb::Config. This is ignored if img is an absolute # path or full URL. # @option opts [Boolean] :reload # Override the Merb::Config[:reload_templates] value. If true, a random query param will be appended # to the image url # @option opts [Boolean, String] :timestamp # Override the Merb::Plugins.config[:asset_helpers][:asset_timestamp] value. If true, a timestamp query param will be appended # to the image url. The value will be File.mtime(Merb.dir_for(:public) / path). # If String is passed than it will be used as the timestamp. # # All other options set HTML attributes on the tag. # # @example # image_tag('foo.gif') # # => # # image_tag('foo.gif', :class => 'bar') # # => # # image_tag('foo.gif', :path => '/files/') # # => # # image_tag('http://test.com/foo.gif') # # => # # image_tag('charts', :path => '/dynamic/') # or # image_tag('/dynamic/charts') # # => # # @return [String] def image_tag(img, opts={}) return "" if img.blank? if img[0].chr == Merb::Const::SLASH opts[:src] = "#{Merb::Config[:path_prefix]}#{img}" else opts[:path] ||= if img =~ ABSOLUTE_PATH_REGEXP absolute = true '' else "#{Merb::Config[:path_prefix]}/images/" end opts[:src] ||= opts.delete(:path) + img end opts[:src] = append_query_string(opts[:src], opts.delete(:reload), opts.delete(:timestamp), !absolute) %{} end # :section: JavaScript related functions # # ==== Parameters # javascript:: Text to escape for use in JavaScript. # # ==== Examples # escape_js("'Lorem ipsum!' -- Some guy") # # => "\\'Lorem ipsum!\\' -- Some guy" # # escape_js("Please keep text\nlines as skinny\nas possible.") # # => "Please keep text\\nlines as skinny\\nas possible." def escape_js(javascript) (javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" } end # ==== Parameters # data:: # Object to translate into JSON. If the object does not respond to # :to_json, then data.inspect.to_json is returned instead. # # ==== Examples # js({'user' => 'Lewis', 'page' => 'home'}) # # => "{\"user\":\"Lewis\",\"page\":\"home\"}" # # js([ 1, 2, {"a"=>3.141}, false, true, nil, 4..10 ]) # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]" def js(data) if data.respond_to? :to_json data.to_json else data.inspect.to_json end end # :section: External JavaScript and Stylesheets # # You can use require_js(:prototype) or require_css(:shinystyles) # from any view or layout, and the scripts will only be included once # in the head of the final page. To get this effect, the head of your # layout you will need to include a call to include_required_js and # include_required_css. # # ==== Examples # # File: app/views/layouts/application.html.erb # # # # <%= include_required_js %> # <%= include_required_css %> # # # <%= catch_content :layout %> # # # # # File: app/views/whatever/_part1.herb # # <% require_js 'this' -%> # <% require_css 'that', 'another_one' -%> # # # File: app/views/whatever/_part2.herb # # <% require_js 'this', 'something_else' -%> # <% require_css 'that' -%> # # # File: app/views/whatever/index.herb # # <%= partial(:part1) %> # <%= partial(:part2) %> # # # Will generate the following in the final page... # # # # # # # # . # . # . # # # See each method's documentation for more information. # :section: Bundling Asset Files # # The key to making a fast web application is to reduce both the amount of # data transfered and the number of client-server interactions. While having # many small, module Javascript or stylesheet files aids in the development # process, your web application will benefit from bundling those assets in # the production environment. # # An asset bundle is a set of asset files which are combined into a single # file. This reduces the number of requests required to render a page, and # can reduce the amount of data transfer required if you're using gzip # encoding. # # Asset bundling is always enabled in production mode, and can be optionally # enabled in all environments by setting the :bundle_assets value # in config/merb.yml to +true+. # # ==== Examples # # In the development environment, this: # # js_include_tag :prototype, :lowpro, :bundle => true # # will produce two # # <% require_js 'jquery', 'effects' %> # # A subsequent call to include_required_js will render... # # => # # # def require_js(*js) @required_js ||= [] @required_js << js end # All javascript files to include, without duplicates. # # ==== Parameters # options:: Default options to pass to js_include_tag. def required_js(options = {}) extract_required_files(@required_js, options) end # The require_css method can be used to require any CSS file anywhere in # your templates. Regardless of how many times a single stylesheet is # included with require_css, Merb will only include it once in the header. # # ==== Parameters # *css<~to_s>:: CSS files to include. # # ==== Examples # <% require_css('style') %> # # A subsequent call to include_required_css will render... # # => # # <% require_css('style', 'ie-specific') %> # # A subsequent call to include_required_css will render... # # => # # # def require_css(*css) @required_css ||= [] @required_css << css end # All css files to include, without duplicates. # # ==== Parameters # options:: Default options to pass to css_include_tag. def required_css(options = {}) extract_required_files(@required_css, options) end # A method used in the layout of an application to create + # # # my_action.herb has a call to require_js 'jquery', 'effects', 'validation' # # File: layout/application.html.erb # include_required_js # # => # # # # # def include_required_js(options = {}) required_js(options).map { |req_js| js_include_tag(*req_js) }.join end # A method used in the layout of an application to create ++ tags for # CSS stylesheets required in in templates and subtemplates using # require_css. # # ==== Parameters # options:: Options to pass to css_include_tag. # # ==== Returns # String:: The CSS tag. # # ==== Options # :bundle<~to_s>:: # The name of the bundle the stylesheets should be combined into. # :media<~to_s>:: # The media attribute for the generated link element. Defaults to :all. # # ==== Examples # # my_action.herb has a call to require_css 'style' # # File: layout/application.html.erb # include_required_css # # => # # # my_action.herb has a call to require_css 'style', 'ie-specific' # # File: layout/application.html.erb # include_required_css # # => # # # def include_required_css(options = {}) required_css(options).map { |req_js| css_include_tag(*req_js) }.join end # Generate JavaScript include tag(s). # # @param [Array] scripts # The scripts to include. If the last element is a Hash, it will be used # as options (see below). If ".js" is left out from the script names, it # will be added to them. # # ==== Options # :charset<~to_s>:: # Charset which will be used as value for charset attribute # :bundle<~to_s>:: # The name of the bundle the scripts should be combined into. # :prefix<~to_s>:: # prefix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:js_prefix] # :suffix<~to_s>:: # suffix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:js_suffix] # :reload:: # Override the Merb::Config[:reload_templates] value. If true, a random query param will be appended # to the js url # @option opts [Boolean, String] :timestamp # Override the Merb::Plugins.config[:asset_helpers][:asset_timestamp] value. If true, a timestamp query param will be appended # to the image url. The value will be File.mtime(Merb.dir_for(:public) / path). # If String is passed than it will be used as the timestamp. # # @example # js_include_tag 'jquery' # # => # # js_include_tag 'jquery', :charset => 'iso-8859-1' # # => # # js_include_tag 'moofx.js', 'upload' # # => # # # # js_include_tag :effects # # => # # js_include_tag :jquery, :validation # # => # # # # js_include_tag :application, :validation, :prefix => "http://cdn.example.com" # # => # # # # js_include_tag :application, :validation, :suffix => ".#{MyApp.version}" # # => # # # # @return [String] The JavaScript include tag(s). def js_include_tag(*scripts) options = scripts.last.is_a?(Hash) ? scripts.pop : {} return nil if scripts.empty? js_prefix = options[:prefix] || Merb::Plugins.config[:asset_helpers][:js_prefix] js_suffix = options[:suffix] || Merb::Plugins.config[:asset_helpers][:js_suffix] if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && scripts.size > 1 bundler = Merb::Assets::JavascriptAssetBundler.new(bundle_name, *scripts) bundled_asset = bundler.bundle! return js_include_tag(bundled_asset) end tags = "" for script in scripts src = js_prefix.to_s + asset_path(:javascript, script) if js_suffix ext_length = ASSET_FILE_EXTENSIONS[:javascript].length + 1 src.insert(-ext_length,js_suffix) end src = append_query_string(src, options.delete(:reload), options.delete(:timestamp)) attrs = { :src => src, :type => "text/javascript", :charset => options[:charset] || "utf-8" } tags << %Q{} end return tags end # Generate CSS include tag(s). # # @param [Array<*String, Hash>] stylesheets # The stylesheets to include. If the last element is a Hash, it will be # used as options (see below). If ".css" is left out from the stylesheet # names, it will be added to them. # # ==== Options # @option opts charset # Charset which will be used as value for charset attribute # @option opts bundle # The name of the bundle the stylesheets should be combined into. # @option opts media # The media attribute for the generated link element. Defaults to :all. # @option opts prefix # prefix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:css_prefix] # @option opts suffix # suffix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:css_suffix] # @option opts reload # Override the Merb::Config[:reload_templates] value. If true, a random query param will be appended # to the css url # @option opts [Boolean, String] :timestamp # Override the Merb::Plugins.config[:asset_helper][:asset_timestamp] value. If true, a timestamp query param will be appended # to the image url. The value will be File.mtime(Merb.dir_for(:public) / path). # If String is passed than it will be used as the timestamp. # # @example # css_include_tag 'style' # # => # # css_include_tag 'style.css', 'layout' # # => # # # # css_include_tag :menu # # => # # css_include_tag :style, :screen # # => # # # # css_include_tag :style, :media => :print # # => # # css_include_tag :style, :charset => 'iso-8859-1' # # => # # css_include_tag :style, :prefix => "http://static.example.com" # # => # # css_include_tag :style, :suffix => ".#{MyApp.version}" # # => # # @return [String] The CSS include tag(s) def css_include_tag(*stylesheets) options = stylesheets.last.is_a?(Hash) ? stylesheets.pop : {} return nil if stylesheets.empty? css_prefix = options[:prefix] || Merb::Plugins.config[:asset_helpers][:css_prefix] css_suffix = options[:suffix] || Merb::Plugins.config[:asset_helpers][:css_suffix] if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && stylesheets.size > 1 bundler = Merb::Assets::StylesheetAssetBundler.new(bundle_name, *stylesheets) bundled_asset = bundler.bundle! return css_include_tag(bundled_asset) end tags = "" reload = options.delete(:reload) timestamp = options.delete(:timestamp) for stylesheet in stylesheets href = css_prefix.to_s + asset_path(:stylesheet, stylesheet) if css_suffix ext_length = ASSET_FILE_EXTENSIONS[:stylesheet].length + 1 href.insert(-ext_length,css_suffix) end href = append_query_string(href, reload, timestamp) attrs = { :href => href, :type => "text/css", :rel => "Stylesheet", :charset => options[:charset] || "utf-8", :media => options[:media] || :all } tags << %Q{} end return tags end # ==== Parameters # *assets:: # The assets to include. These should be the full paths to any static served file # # ==== Returns # Array:: Full unique paths to assets OR # String:: if only a single path is requested # ==== Examples # uniq_path("/javascripts/my.js","/javascripts/my.css") # #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/javascripts/my.css"] # # uniq_path(["/javascripts/my.js","/stylesheets/my.css"]) # #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"] # # uniq_path(%w(/javascripts/my.js /stylesheets/my.css)) # #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"] # # uniq_path('/stylesheets/somearbitrary.css') # #=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css" # # uniq_path('/images/hostsexypicture.jpg') # #=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg" def uniq_path(*assets) paths = [] assets.flatten.each do |filename| paths.push(Merb::Assets::UniqueAssetPath.build(filename)) end paths.length > 1 ? paths : paths.first end # ==== Parameters # *assets:: # Creates unique paths for javascript files (prepends "/javascripts" and appends ".js") # # ==== Returns # Array:: Full unique paths to assets OR # String:: if only a single path is requested # ==== Examples # uniq_js_path("my") # #=> "http://assets2.my-awesome-domain.com/javascripts/my.js" # # uniq_js_path(["admin/secrets","home/signup"]) # #=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js", # "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"] def uniq_js_path(*assets) paths = [] assets.flatten.each do |filename| paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:javascript,filename))) end paths.length > 1 ? paths : paths.first end # ==== Parameters # *assets:: # Creates unique paths for stylesheet files (prepends "/stylesheets" and appends ".css") # # ==== Returns # Array:: Full unique paths to assets OR # String:: if only a single path is requested # ==== Examples # uniq_css_path("my") # #=> "http://assets2.my-awesome-domain.com/stylesheets/my.css" # # uniq_css_path(["admin/secrets","home/signup"]) # #=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css", # "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"] def uniq_css_path(*assets) paths = [] assets.flatten.each do |filename| paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:stylesheet,filename))) end paths.length > 1 ? paths : paths.first end # ==== Parameters # *assets:: # As js_include_tag but has unique path # # ==== Returns # Array:: Full unique paths to assets OR # String:: if only a single path is requested # ==== Examples # uniq_js_tag("my") # #=> def uniq_js_tag(*assets) js_include_tag(*uniq_js_path(assets)) end # ==== Parameters # *assets:: # As uniq_css_tag but has unique path # # ==== Returns # Array:: Full unique paths to assets OR # String:: if only a single path is requested # ==== Examples # uniq_css_tag("my") # #=> def uniq_css_tag(*assets) css_include_tag(*uniq_css_path(assets)) end private # Helper method to filter out duplicate files. # # ==== Parameters # options:: Options to pass to include tag methods. def extract_required_files(files, options = {}) return [] if files.nil? || files.empty? seen = [] files.inject([]) do |extracted, req_js| include_files, include_options = if req_js.last.is_a?(Hash) [req_js[0..-2], options.merge(req_js.last)] else [req_js, options] end seen += (includes = include_files - seen) extracted << (includes + [include_options]) unless includes.empty? extracted end end def append_query_string(path, random, timestamp, allow_default = true) random = AssetsMixin.append_random_query_string?(random, allow_default) timestamp = AssetsMixin.append_timestamp_query_string?(timestamp, allow_default) query_string = if random random_query_string elsif timestamp timestamp == true ? timestamp_for_asset(path) : timestamp end if query_string path + (path.include?('?') ? "&#{query_string}" : "?#{query_string}") else path end end def random_query_string Time.now.strftime("%m%d%H%M%S#{rand(99)}") end def timestamp_for_asset(path) if path !~ ABSOLUTE_PATH_REGEXP begin File.mtime(Merb.dir_for(:public) / path).to_i rescue Merb.logger.warn "#{self.class}: Unable to get mtime for #{path}" end end end end end merb-assets-1.1.3/lib/merb-assets.rb0000644000175000017500000000155211755425071016577 0ustar tfheentfheenrequire 'merb-core' require 'merb-assets/assets' require 'merb-assets/assets_mixin' Merb::BootLoader.before_app_loads do Merb::Controller.send(:include, Merb::AssetsMixin) end Merb::Plugins.config[:asset_helpers] = { :max_hosts => 4, :asset_domain => "assets%s", :domain => "my-awesome-domain.com", :use_ssl => false, :asset_timestamp => false, # Global prefix/suffix for css/js include tags, overridable in js_include_tag and css_include_tag # # :js_prefix => "http://cdn.example.com" # require_js :application # => "http://cdn.example.com/javascripts/application.js" # # :js_suffix => "_#{MyApp.version}" # require_js :application # => "/javascripts/application_0.2.2.js" :js_prefix => nil, :js_suffix => nil, :css_prefix => nil, :css_suffix => nil } if Merb::Plugins.config[:asset_helpers].nil?