Burak's Journal http://use.perl.org/~Burak/journal/ Burak's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-02-08T22:45:10+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 Burak's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~Burak/journal/ reftype() lazziness http://use.perl.org/~Burak/journal/39605?from=rss <p>I was doing a lot of <code>foo() if ref($thing) eq 'ARRAY'</code> or <code>foo() if ref($thing) eq 'HASH'</code> (even something idiotic like <code>foo() if ref($thing) &amp;&amp; "$thing" =~ m{.+?=HASH(0x.+?)}</code>) checks inside a pet project of mine. So thought about making it in an elegant way instead. I mean <code>ref($thing)-&gt;array</code> or even <code>ref($thing)-&gt;is_array</code> seemed much better as a syntactic sugar. However <code>ref()</code> is clearly not the way to go for the implementation as it fails to identify the underlying type of objects. So, the obvious choice is <code>Scalar::Util::reftype</code>. I've named the module <a href="http://search.cpan.org/dist/Scalar-Util-Reftype/">Scalar::Util::Reftype</a>. In a way, I can say that it's similar to <code>File::stat</code>. Btw, <code>Scalar::Util::reftype</code> has one oddity: unlike <code>CORE::ref</code> it returns undef if you pass a non-ref parameter to it. So, instead of <code>foo() if reftype($thing) eq 'ARRAY'</code> one must say <code>foo() if defined reftype($thing) &amp;&amp; reftype($thing) eq 'ARRAY'</code> or just <code>foo() if reftype($thing) &amp;&amp; reftype($thing) eq 'ARRAY'</code> to prevent an annoying warning:</p><p><code><br>C:\&gt;perl -MScalar::Util=reftype -wle "my $x; print reftype($x) eq 'ARRAY'"<br>Use of uninitialized value in string eq at -e line 1.</code></p><p>It also can not detect <code>Regexp</code> (<code>CORE::ref</code> can, as long as it's not blessed):</p><p><code><br>C:\&gt;perl -MScalar::Util=reftype -wle "my $x = qr//; print reftype $x"<br>SCALAR</code></p><p><code>C:\&gt;perl -wle "my $x = qr//; print ref $x"<br>Regexp</code></p><p><code>C:\&gt;</code></p><p>Fortunately, perl 5.10 comes with <code>re::is_regexp</code> to detect if an object is based on a regex or not. But what about older perls? We can remedy the situation with the help of <a href="http://search.cpan.org/dist/Data-Dump-Streamer/lib/Data/Dump/Streamer.pm">Data::Dump::Streamer::regex</a> under at least perl 5.8.x. Unfortunately Data::Dump::Streamer seems to fail under anything older than that. I wasn't aware that <code>re::is_regexp</code> is a new functionality until reached "<a href="http://perlmonks.org/?node_id=665339">ref() and Regexp</a>" discussion on PerlMonks.</p><p>I also checked <code>ref</code> documentation. As of perl 5.10 it lists these reference types:</p><p><code><br>SCALAR<br>ARRAY<br>HASH<br>CODE<br>REF<br>GLOB<br>LVALUE<br>FORMAT<br>IO<br>VSTRING<br>Regexp<br></code></p><p>Only perl 5.10's ref seems to detect VSTRING refs and since they are deprecated and the usage seems to be rare, the module does not support them. Also FORMAT is only available in perl 5.8 and newer. But frankly, I can't imagine anyone creating refs/objects based on LVALUE, FORMAT or VSTRING (hmmm... maybe only TheDamian). So, they exist only for the sake of compatibility. For the Regexp type, I've just added a dynamic dependency on Data::Dump::Streamer if <code>Scalar::Util::Reftype</code> is tried to be installed under anything older than perl 5.10.</p><p>The interface is simple. Just <code>use</code> the module to get a brand new <code>reftype</code> function:</p><p><code><br> &nbsp; &nbsp; &nbsp; &nbsp; use Scalar::Util::Reftype;</code></p><p><code> &nbsp; &nbsp; &nbsp; &nbsp; foo() if reftype( "string" )-&gt;hash; # foo() will never be called<br> &nbsp; &nbsp; &nbsp; &nbsp; bar() if reftype( \$var )-&gt;scalar; # bar() will be called<br> &nbsp; &nbsp; &nbsp; &nbsp; baz() if reftype( [] )-&gt;array; # baz() will be called<br> &nbsp; &nbsp; &nbsp; &nbsp; xyz() if reftype( sub {} )-&gt;array; # xyz() will never be called</code></p><p><code> &nbsp; &nbsp; &nbsp; &nbsp; $obj = bless {}, "Foo";<br> &nbsp; &nbsp; &nbsp; &nbsp; my $rt = reftype( $obj );<br> &nbsp; &nbsp; &nbsp; &nbsp; $rt-&gt;hash; # false<br> &nbsp; &nbsp; &nbsp; &nbsp; $rt-&gt;hash_object; # true<br> &nbsp; &nbsp; &nbsp; &nbsp; $rt-&gt;class; # "Foo"<br></code></p><p><code>reftype</code> will create an object based on the parameter you specified and it is possible to call test methods on the return value. It currently has these test methods:</p><p><code><br>scalar<br>array<br>hash<br>code<br>glob<br>lvalue<br>format<br>ref<br>io<br>regexp<br>scalar_object<br>array_object<br>hash_object<br>code_object<br>glob_object<br>lvalue_object<br>format_object<br>ref_object<br>io_object<br>regexp_object<br>class<br></code></p><p>Here, <code>class</code> can be thought as analogous to Scalar::Util' s blessed function. It returns the package/class name of the reference if it happens to be a blessed reference. The rest of the methods test if the parameter matches the type they define.</p><p>Oh, I've also overloaded the object <code>Scalar::Util::Reftype:reftype</code> returns, to be sure that it will not be used in boolean contexts. If one makes such a thing, then the code will suffer the consequences<nobr> <wbr></nobr>:)</p> Burak 2009-09-10T03:24:00+00:00 journal Parse::HTTP::UserAgent: yet another user agent string parser http://use.perl.org/~Burak/journal/39577?from=rss <p>I was using <a href="http://search.cpan.org/dist/HTTP-BrowserDetect/">HTTP::BrowserDetect</a> for a long time. Not because it's a pice of art or accurate, but because of <a href="http://c2.com/cgi/wiki?LazinessImpatienceHubris">laziness</a> perhaps. When I had some free time, I thought about re-inventing the wheel, like <a href="http://search.cpan.org/~burak/">I did several times</a> before. The main reason for re-inventing is the source code and interface of the module (try to read it, you'll understand) and the lack of new releases. Also, it's not accurate.</p><p>There are two other alternatives though: <a href="http://search.cpan.org/dist/HTML-ParseBrowser/">HTML::ParseBrowser</a> and <a href="http://search.cpan.org/dist/HTTP-DetectUserAgent/">HTTP::DetectUserAgent</a>. The former is really good parser-wise, while the latter is actually a sniffer and does not give you a verbose result.</p><p>So, I wrote <a href="http://search.cpan.org/dist/Parse-HTTP-UserAgent/">Parse::HTTP::UserAgent</a>. It tries to be verbose and parse as much as possible from the junk named "User Agent String". It tries to identify the major browsers first and then falls back to minor/old ones with an extended probe. The parsed structure has many fields like:</p><blockquote><div><p> <tt>name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Browser name. You may need to check original_name() if faker (like Maxthon).<br>version_raw&nbsp; &nbsp; &nbsp; &nbsp; Browser version<br>version&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; version(version_raw)-&gt;numify: The float version of the parsed version.<br>original_name&nbsp; &nbsp; &nbsp; The original name (i.e.: Maxthon)<br>original_version&nbsp; &nbsp;The original version (i.e.: 2.0 (Maxthon))<br>os&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Operating system. Windows names returned instead of versions<br>lang&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;The "user interface" language of the browser<br>toolkit&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [tk_name, tk_version, version(tk_version)-&gt;numify]. Gecko, Trident, etc.<br>dotnet&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If it has<nobr> <wbr></nobr>.NET CLR version in the string, this'll have all versions<br>mozilla&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; If a Mozilla browser, returns Moz version: [original, version(original)-&gt;numify]<br>strength&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Encryption strength (I guess this does not have much value today)<br>robot&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UA is a robot<br>extras&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Any non-parsable junk. Arrayref.<br>parser&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;The name of the parser that returned the result set<br>generic&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Parsed by a generic parser? Bool.<br>string&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;The original User Agent String<br>unknown&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; User Agent String can not be parsed<br>device&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;***not implemented yet<br>wap&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ***not implemented yet<br>mobile&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;***not implemented yet</tt></p></div> </blockquote><p>The module also has <code>-&gt;as_hash</code> and <code>-&gt;dumper</code> methods for debugging purposes.</p><p>The biggest difference is; it parses the fakers like Maxthon accurately. Also extracts<nobr> <wbr></nobr>.NET versions and toolkit names and versions. It also identifies <a href="http://dev.opera.com/articles/view/opera-ua-string-changes/">Opera 10</a> (btw, Opera is the first thing I install on a new system) correctly.</p><p>The version numbers are converted to decimals to ease comparison (I dislike that major/minor stuff the others implement). The conversion also removes any junk string (like "gold") from the version number. While using <a href="http://search.cpan.org/dist/version/">version</a> is good, as it handles all the nasty stuff, I got some regression from 5.6.2 smokers after releasing the module. It looks like they (5.6.2) have the pure perl version::vpp (I couldn't compile the xs version under 5.6.1 either) which has some kind of bug. I've opened a <a href="http://rt.cpan.org/Public/Bug/Display.html?id=49348">ticket about the issue</a>, but also added a workaround to fool version::vpp (postfix '.0' if version is three digits). I currently have no idea about 5.5.x but 5.6.x seem to be fine at least (also tested myself with ActivePerl 5.6.1 on a virtual Windows XP).</p><p>The module also has some example programs in it for benchmarking. I'll give some figures below. The test system is: Windows Vista Home Premium SP2 32bit &amp; P8600 @ 2.40GHz &amp; ActivePerl 5.10.0.1004</p><blockquote><div><p> <tt>C:\&gt;perl -Ilib eg\bench.pl -c 1000<br>*** The data integrity is not checked in this run.<br>*** This is a benchmark for parser speeds.<br>*** Testing 161 User Agent strings on each module with 1000 iterations each.<br> &nbsp; <br>This may take a while. Please stand by<nobr> <wbr></nobr>...<br> &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Rate&nbsp; &nbsp; HTML&nbsp; &nbsp;HTML2 Browser&nbsp; &nbsp;Parse&nbsp; Parse2&nbsp; Detect<br>HTML&nbsp; &nbsp; 12.6/s&nbsp; &nbsp; &nbsp; --&nbsp; &nbsp; &nbsp;-2%&nbsp; &nbsp; -63%&nbsp; &nbsp; -75%&nbsp; &nbsp; -82%&nbsp; &nbsp; -90%<br>HTML2&nbsp; &nbsp;12.9/s&nbsp; &nbsp; &nbsp; 2%&nbsp; &nbsp; &nbsp; --&nbsp; &nbsp; -62%&nbsp; &nbsp; -75%&nbsp; &nbsp; -81%&nbsp; &nbsp; -90%<br>Browser 34.2/s&nbsp; &nbsp; 170%&nbsp; &nbsp; 166%&nbsp; &nbsp; &nbsp; --&nbsp; &nbsp; -33%&nbsp; &nbsp; -51%&nbsp; &nbsp; -73%<br>Parse&nbsp; &nbsp;51.1/s&nbsp; &nbsp; 304%&nbsp; &nbsp; 297%&nbsp; &nbsp; &nbsp;50%&nbsp; &nbsp; &nbsp; --&nbsp; &nbsp; -26%&nbsp; &nbsp; -59%<br>Parse2&nbsp; 69.4/s&nbsp; &nbsp; 449%&nbsp; &nbsp; 439%&nbsp; &nbsp; 103%&nbsp; &nbsp; &nbsp;36%&nbsp; &nbsp; &nbsp; --&nbsp; &nbsp; -44%<br>Detect&nbsp; &nbsp;125/s&nbsp; &nbsp; 888%&nbsp; &nbsp; 871%&nbsp; &nbsp; 266%&nbsp; &nbsp; 144%&nbsp; &nbsp; &nbsp;80%&nbsp; &nbsp; &nbsp; --<br> &nbsp; <br>The code took: 241.65 wallclock secs (228.21 usr +&nbsp; 0.08 sys = 228.29 CPU)<br> &nbsp; <br>---------------------------------------------------------<br> &nbsp; <br>List of abbreviations:<br> &nbsp; <br>HTML&nbsp; &nbsp; &nbsp; HTML::ParseBrowser v1<br>HTML2&nbsp; &nbsp; &nbsp;HTML::ParseBrowser v1 (re-use the object)<br>Browser&nbsp; &nbsp;HTTP::BrowserDetect v0.99<br>Detect&nbsp; &nbsp; HTTP::DetectUserAgent v0.01<br>Parse&nbsp; &nbsp; &nbsp;Parse::HTTP::UserAgent v0.16<br>Parse2&nbsp; &nbsp; Parse::HTTP::UserAgent v0.16 (without extended probe)</tt></p></div> </blockquote><p>HTML::ParseBrowser is slow as hell. Even re-using the object as the doc suggests does not help. It's good that I wasn't aware of the module until now<nobr> <wbr></nobr>:p HTTP::BrowserDetect is not a good performer too. But the interface is extensive and it's kinda defacto standard in this area. It tries to match with *anything* possible and this choice slows it down (who cares if $ua-&gt;win31 is true as of today right?). HTTP::DetectUserAgent is the speedy one here. It doubles Parse::HTTP::UserAgent even when the extended probe is disabled. However it gains this speed with several CAVEATs as the version number suggests.</p><blockquote><div><p> <tt>C:\&gt;perl -Ilib eg\accuracy.pl<br>*** This is a test to compare the accuracy of the parsers.<br>*** The data set is from the test suite. There are 161 UA strings<br>*** Parse::HTTP::UserAgent will detect all of them<br>*** A tiny fraction of the regressions can be related to wrong parsing.<br>*** Equation tests are not performed. Tests are boolean.<br> &nbsp; <br>This may take a while. Please stand by<nobr> <wbr></nobr>...<br> &nbsp; <br>------------------------------------------------------------------------- ---------------------<br>| Parser&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Name FAILS&nbsp; &nbsp; &nbsp;| Version FAILS&nbsp; | Language FAILS | OS FAILS&nbsp; &nbsp; &nbsp; &nbsp;|<br>---------------------------------------------------------------------------<nobr>-<wbr></nobr> ------------------<br>| HTTP::DetectUserAgent&nbsp; |&nbsp; &nbsp;27 -&nbsp; 16.77% |&nbsp; &nbsp;37 -&nbsp; 23.27% |&nbsp; &nbsp;67 - 100.00% |&nbsp; &nbsp;35 -&nbsp; 24.31% |<br>| HTTP::BrowserDetect&nbsp; &nbsp; |&nbsp; &nbsp;28 -&nbsp; 17.39% |&nbsp; &nbsp; 8 -&nbsp; &nbsp;5.03% |&nbsp; &nbsp;67 - 100.00% |&nbsp; &nbsp;20 -&nbsp; 13.89% |<br>| HTML::ParseBrowser&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; 0 -&nbsp; &nbsp;0.00% |&nbsp; &nbsp; 3 -&nbsp; &nbsp;1.89% |&nbsp; &nbsp;42 -&nbsp; 62.69% |&nbsp; &nbsp;19 -&nbsp; 13.19% |<br>| Parse::HTTP::UserAgent |&nbsp; &nbsp; 0 -&nbsp; &nbsp;0.00% |&nbsp; &nbsp; 3 -&nbsp; &nbsp;1.89% |&nbsp; &nbsp; 3 -&nbsp; &nbsp;4.48% |&nbsp; &nbsp; 4 -&nbsp; &nbsp;2.78% |<br>----------------------------------------------------------------------------<nobr>-<wbr></nobr> -----------------</tt></p></div> </blockquote><p>Parse::HTTP::UserAgent is not perfect, but at least it seems to be close. HTML::ParseBrowser is more accurate on name/version matching. Speedy HTTP::DetectUserAgent seems to be the worst. However there is one caveat, the test data is from the Parse::HTTP::UserAgent test suite. So, Parse::HTTP::UserAgent is not actually that good yet since there are some patterns it can not match.</p><p>Note: The module is already on <a href="http://search.cpan.org/dist/Parse-HTTP-UserAgent">CPAN</a>, but you can get the latest code and non-CPAN content from <a href="http://bitbucket.org/burak/cpan-parse-http-useragent/src/">the code repository</a>. The repo also has a <code>etc/Migration.pod</code> for HTTP::BrowserDetect users.</p> Burak 2009-09-04T04:25:35+00:00 journal Having a single version number in all modules in a distro http://use.perl.org/~Burak/journal/37679?from=rss I was trying to figure out a mechanism to somehow format all modules in a distro (Text::Template::Simple) automatically to have a single version number instead of varying versions among files. I'm not so sure if this is the best way, but I chose to manually modify the files to update the versions in them. First, I had to subclass Module::Build to alter the `Build dist` action. However, M::B has an awkward interface for subclassing. One needs to pass the sublass code as a string into the subclass() method. Weirdo<nobr> <wbr></nobr>:p But since I didn't like this interface for subclassing and I wanted to use the syntax checking/coloring of my Komodo Edit, I've decided to load the content from an external file:<br><br>my $class = Module::Build-&gt;subclass(<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; class =&gt; 'MBSubclass',<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code =&gt; raw_subclass(),<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );<br><br>sub raw_subclass {<br> &nbsp; &nbsp; &nbsp; &nbsp; my $file = File::Spec-&gt;catfile( 'tools', 'Build.pm' );<br> &nbsp; &nbsp; &nbsp; &nbsp; my $FH = IO::File-&gt;new;<br> &nbsp; &nbsp; &nbsp; &nbsp; $FH-&gt;open( $file, 'r' ) or die "Can not open($file): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; my $rv = do { local $/; &lt;$FH&gt; };<br> &nbsp; &nbsp; &nbsp; &nbsp; close $FH;<br> &nbsp; &nbsp; &nbsp; &nbsp; return $rv;<br>}<br><br>And here is the subclass (note that there is no package declaration since M::B adds this part automatically afterwards):<br><br>use strict;<br>use vars qw( $VERSION );<br>use warnings;<br>use File::Find;<br>use constant RE_VERSION_LINE =&gt; qr{<br> &nbsp; &nbsp; &nbsp; \A \$VERSION \s+ = \s+ ["'] (.+?) ['"] ; (.+?) \z<br>}xms;<br>use constant VTEMP =&gt; q{$VERSION = '%s';};<br><br>$VERSION = '0.10';<br><br>sub ACTION_dist {<br> &nbsp; &nbsp; &nbsp; my $self = shift;<br> &nbsp; &nbsp; &nbsp; warn sprintf(<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "RUNNING 'dist' Action from subclass %s v%s\n",<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ref($self),<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $VERSION<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );<br> &nbsp; &nbsp; &nbsp; my @modules;<br> &nbsp; &nbsp; &nbsp; find {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wanted =&gt; sub {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $file = $_;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return if $file !~ m{ \. pm \z }xms;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; push @modules, $file;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; warn "FOUND Module: $file\n";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no_chdir =&gt; 1,<br> &nbsp; &nbsp; &nbsp; }, "lib";<br> &nbsp; &nbsp; &nbsp; $self-&gt;_change_versions( \@modules );<br> &nbsp; &nbsp; &nbsp; $self-&gt;SUPER::ACTION_dist( @_ );<br>}<br><br>sub _change_versions {<br> &nbsp; &nbsp; &nbsp; my $self = shift;<br> &nbsp; &nbsp; &nbsp; my $files = shift;<br> &nbsp; &nbsp; &nbsp; my $dver = $self-&gt;dist_version;<br><br> &nbsp; &nbsp; &nbsp; warn "DISTRO Version: $dver\n";<br><br> &nbsp; &nbsp; &nbsp; foreach my $mod ( @{ $files } ) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; warn "PROCESSING $mod\n";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $new = $mod . '.new';<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; open my $RO_FH, '&lt;:raw', $mod or die "Can not open file($mod): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; open my $W_FH , '&gt;:raw', $new or die "Can not open file($new): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $changed;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while ( my $line = readline $RO_FH ) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( ! $changed &amp;&amp; ( $line =~ RE_VERSION_LINE ) ) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $oldv = $1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $remainder = $2;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; warn "CHANGED Version from $oldv to $dver\n";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printf $W_FH VTEMP . $remainder, $dver;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $changed++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; next;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print $W_FH $line;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br><br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close $RO_FH or die "Can not close file($mod): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close $W_FH or die "Can not close file($new): $!";<br><br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unlink($mod) || die "Can not remove original module($mod): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rename( $new, $mod ) || die "Can not rename( $new, $mod ): $!";<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; warn "RENAME Successful!\n";<br> &nbsp; &nbsp; &nbsp; }<br><br> &nbsp; &nbsp; &nbsp; return;<br>}<br><br>It's really straightforward. Find the *.pm and them create a modified copy that has the distro's version and replace the original with the new one and resume `dist` process<nobr> <wbr></nobr>:) Burak 2008-10-16T19:45:10+00:00 journal Text::Template::Simple 0.61 is released http://use.perl.org/~Burak/journal/37599?from=rss <p> You can get if from <a href="http://search.cpan.org/~burak/Text-Template-Simple/lib/Text/Template/Simple.pm">CPAN</a><nobr> <wbr></nobr>:) </p><p> Actually, I've released 0.60 after several development versions. But immediately faced the infamous <a href="http://www.nntp.perl.org/group/perl.qa/2008/09/msg11568.html">World-writable Files</a> thingy. While I <i>still</i> don't think this is some serious security breach (compared to allowing arbitrary Makefile.PLs and Build.PLs entering your system), PAUSE indexer warned me (thanks to <a href="http://www.nntp.perl.org/group/perl.qa/2008/09/msg11603.html">Andreas Koenig's recent change</a>) about world-writable "directories" inside my tarball. Sice I was not using some 3rd party tar command and using Module::Build as the toolkit, I thought that this thing will not affect my distro. But I was wrong. </p><p> I didn't dig this much and both Archive::Tar (which handles archiving) and Module::Build lacked any info regarding this. So, after some quick investigation, as a quick fix, I've modified Module::Build::Base and changed this line in line 3704:</p><blockquote><div><p> <tt>&nbsp; &nbsp;Archive::Tar-&gt;create_archive("$file.tar.gz", 1, @$files);</tt></p></div> </blockquote><p>into this (removed adding directories to tar)</p><blockquote><div><p> <tt>&nbsp; &nbsp;Archive::Tar-&gt;create_archive("$file.tar.gz", 1, grep { !-d $_ } @$files);</tt></p></div> </blockquote><p>which seemed to solve my problem. I even opened a bug in the <a href="http://rt.cpan.org/Public/Bug/Display.html?id=39804">Module::Build RT Queue</a>. I hope they'll apply this or find a better way to fix the tarball issue. And as I said in the RT BUG: I'm surprised that <a href="http://www.nntp.perl.org/group/perl.qa/2008/09/msg11568.html">no one in the email thread</a> seem to use this trio as their environment: Windows + Module::Build + Archive::Tar<nobr> <wbr></nobr>:p </p><p> Anyway, lets return to the subject. I've released a new version of <a href="http://search.cpan.org/~burak/Text-Template-Simple/lib/Text/Template/Simple.pm">Text::Template::Simple</a> and it is kind of a milestone release including these new stuff: </p><ul> <li>Dynamic Includes (a.k.a processed includes)</li><li>Interpolation in includes</li><li>Chomping (global &amp; per directive)</li><li>Template name access through $0</li><li>Explicit types to compile()</li></ul><p> Chomping is similar to what TT has and maybe more. The biggest and tricky part was the dynamic includes and interpolation in includes. I've implemented that stuff several times before reaching it's current status (actually same thing happened with chomping). Includes currently miss stuff like parameter passing and applying filters, but I'll add these features eventually. At the moment it is possible to use things like:</p><blockquote><div><p> <tt>&lt;% my $file = "t/data/interpolate_data"; %&gt;<br>&lt;%* $file . ".tts" %&gt; # dynamic<br>&lt;%+ $file . ".tts" %&gt; # static</tt></p></div> </blockquote><p>or without interpolation:</p><blockquote><div><p> <tt>&lt;%* t/data/interpolate_data.tts %&gt; # dynamic<br>&lt;%+ t/data/interpolate_data.tts %&gt; # static</tt></p></div> </blockquote><p>And chomping:</p><blockquote><div><p> <tt>Test<br>&nbsp; &nbsp;&lt;%=- $foo -%&gt;<br>123</tt></p></div> </blockquote><p>Template name access:</p><blockquote><div><p> <tt>&nbsp; &nbsp;I am &lt;%= $0 %&gt;</tt></p></div> </blockquote><p>See <a href="http://search.cpan.org/~burak/Text-Template-Simple/lib/Text/Template/Simple.pm">the documentation</a> for more information. </p><p> I like TT's features and even have to use it @ $work, but I need a non-mini-language thing. And CPAN is filled with re-invented wheels right?<nobr> <wbr></nobr>:) </p> Burak 2008-10-03T20:00:32+00:00 journal Hello World http://use.perl.org/~Burak/journal/36901?from=rss <p>I don't know how long I've been a user in use Perl, but this is my first journal entry. Yay!<nobr> <wbr></nobr>:)</p><p>I've released <a href="http://search.cpan.org/dist/Sys-Info/">Sys::Info</a> 0.60 today. It's a milestone version that has mostly compatible Linux &amp; Windows &amp; Unknown (Generic) drivers. Windows OS driver now supports Windows Server 2008 and a lot of other Windows editions too. Windows Server 2008 support was a little bit tricky since Microsoft did not bump the version number with this os release (unlike Server 2003) and it has the same version number as Windows Vista. It is only detectable through the editions.</p><p>For the Windows driver, my original plan was to drop WMI interface and use Win32::API, however I've dropped Win32::API idea in favor of XS and WMI turned out to be some huge beast that can not be duplicated easily (or not at all). I was lost on MSDN on this subject<nobr> <wbr></nobr>:p</p><p>Linux driver also has improved OS support too. I've implemeted several OS meta keys and also tried to mimic the "Edition" information for distros. Currently, only Ubuntu is supported by the edition() method.</p><p>There is also a new cdkey() function to return the cdkeys for the OS and Office software. You can guess that this only has a meaning and only implemeted in the Windows driver<nobr> <wbr></nobr>:) It's basically a shortcut to learn the cdkey quickly in case you need it. Original code for that was taken from a PerlMonks thread.</p><p>There are some improvements on the CPU detection side too. Hyper Threading detection is improved and it now returns the number of threads if Hyper Threading is in effect. Also, the data structure now has the "architecture" key. However the load() method has a caveat it returns the current CPU usage instead of the load average (which does not exist in Windows anyway).</p><p>Sys::Info was initiated back in 2004 while I was supposed to write down my undergraduate thesis some time late at night (3 am Eternal<nobr> <wbr></nobr>:p) and evolved from that. The idea was to display the OS &amp; CPU name (and HTTP Server name) correctly in a CMS system I was (and still -- I'm lazy --) working on, but this thing resulted with a module suite. The first CPAN release was two years later from that... </p><p>I'm trying to create a single and mostly equal interface between the OS specific drivers for system information but it turned out that this is not as easy as I thought back then. </p><p>Future plans:</p><ul> <li> Improving current drivers (Windows/Linux/Unknown).</li><li><ul> <li>- Maybe split the drivers into their own distros.</li></ul></li><li> Creating a separate distro for Sys::Info::Device::BIOS</li><li> Adding support for some other devices</li><li> Create a mechanism for drop-in driver/device system.</li><li> (In a far far future) Create a *BSD driver (which I didn't even use once 'till now)</li><li> (In a far far future) If (somehow) I can have access to a Mac(book(\s?Pro|)?); create a MacOSX (darwin?) driver</li></ul><p> Patches &amp; Suggestions are welcome as always<nobr> <wbr></nobr>:) </p><blockquote><div><p> <tt>perl -MSys::Info -wle "sub n{Sys::Info-&gt;os-&gt;name(@_)} print for n(),n(long=&gt;1),n(edition=&gt;1),n(edition=&gt;1,long=&gt;1)"</tt></p></div> </blockquote><p>Example outputs:</p><blockquote><div><p> <tt>(1)<br> <br>Windows Server 2008<br>Windows Server 2008 Service Pack 1 build 6001<br>Windows Server 2008 Enterprise Edition Full Installation<br>Windows Server 2008 Enterprise Edition Full Installation Service Pack 1 build 6001<br> <br>(2)<br> <br>Windows Vista<br>Windows Vista Service Pack 1 build 6001<br>Windows Vista Enterprise Edition<br>Windows Vista Enterprise Edition Service Pack 1 build 6001<br> <br>(3)<br> <br>Windows XP<br>Windows XP Service Pack 3 build 2600<br>Windows XP Professional<br>Windows XP Professional Service Pack 3 build 2600</tt></p></div> </blockquote><p>And here is an Ubuntu output<nobr> <wbr></nobr>;)</p><blockquote><div><p> <tt>perl -MSys::Info -wle 'sub n{Sys::Info-&gt;os-&gt;name(@_)} print for n(),n(long=&gt;1),n(edition=&gt;1),n(edition=&gt;1,long=&gt;1)'<br> <br>Ubuntu Linux<br>Ubuntu Linux 8.04 (kernel: 2.6.24-19-generic)<br>Ubuntu Linux (Hardy Heron)<br>Ubuntu Linux (Hardy Heron) 8.04 (kernel: 2.6.24-19-generic)</tt></p></div> </blockquote> Burak 2008-07-13T14:32:09+00:00 journal