I Use This!
Activity Not Available

News

Analyzed about 1 month ago.
Posted almost 19 years ago by Daniel Berger
It’s often been said that Perl’s greatest strength is CPAN, Perl’s vast collection of free libraries contributed by developers from around the world. Recently I started to wonder about RubyForge and how RubyForge stacks up against CPAN in general.1 ... [More] First, length of service. CPAN has been around for 12 years (October 1995). RubyForge has been in existence for just over 4 years (July, 2003). Second, the number of users. RubyForge boasts over 20,300 users. CPAN, on the other hand, has far less at just over 6,150 registered users.2 Not every registered user is associated with a project, however. There are 3635 users are associated with a project on RubyForge, while on CPAN there are 3774 users associated with at least one library. Of the 3635 users on RubyForge, 849 are associated with more than one project.3 Third, the number of libraries. CPAN boasts approximately 13,500 separate libraries. RubyForge currently has approximately 5000 separate libraries, organized into about 4800 projects. That means, on average, most projects have one library, but some have multiple libraries per project.4 While RubyForge has far fewer libaries than CPAN, the ratio isn’t nearly as large as I would have thought. Quick aside. I didn’t do any real analysis against Python, but the home page for the Vaults of Parnassus shows 2025 libraries. Fourth, library quality and usefulness (more subjective here). There’s a lot of overlap and, well, cruft on CPAN.5 There are over 300 Acme (joke) modules. There are multiple wrappers for the same underlying library, such as many of the “Tiny” and “Simple” modules. There are libraries that should have been bundled together but weren’t, such as the various Chemistry::PointGroup libs. There are also libraries that have similar or identical functionality to other libraries, such as many of the List and/or Array libraries. On top of that, a healthy chunk of the Perl libraries on CPAN are either unnecessary in Ruby or contain behavior that’s already baked into Ruby itself. Examples include a large collection of OO modules (Class::Accessors and the like), a large number of modules that create various IO, Number, File, Array, String and Hash classes, and related methods, that Ruby has builtin (Array, Array::List, File::chmod, and so on), over 200 “Tie” modules (Ruby doesn’t need ‘tie’), over 90 libraries for interacting with CPAN or the RT backend itself (I only know of one library for RubyForge), and equivalent libraries that are already part of Ruby’s standard library (e.g. libwww). Last, release frequency. Between August 14th and September 14th there were 1133 releases from 690 distinct libraries on CPAN 6. RubyForge, by contrast, had 612 releases in the same date range (although I wasn’t sure how many of them were from distinct libraries at the time of this writing). So, slightly less than half of CPAN at the moment. What do all these numbers mean? Good question. I think, at the very least, it means that the Ruby community is doing very well in terms of library development and releases. I give Tom Copeland a huge amount of credit for that, in that I think the very act of creating RubyForge fostered an atmosphere of development (collaborative or otherwise) and inspired programmers new to Ruby to take the step of releasing their own software. I can’t prove it, of course. It’s just a gut feeling I have after watching the Ruby community grow for seven years. It also means that Perl is still going strong, cruft and all. You can’t really argue too much with their release rate, and some of it is really good stuff, too. I would say that CPAN still has the edge in database interfaces, Apache libraries and wrappers for 3rd party commercial libraries, among a few other things.[7] But, we’re catching up, and fast. :) See you next Wednesday.[8] 1 When I say “CPAN”, I’m generally referring to search.cpan.org plus RT. 2 I scraped the Authors pages to get the total. At the time of this writing it was 6152, although a handful of these appear to be generic logins. 3 CPAN isn’t a collaborative development environment, so there may be multiple users actively associated with a given library, but there’s no way to tell without manually digging through files. 4This number does not include a number of libraries listed on the RAA that are not on RubyForge. I’d make a very rough guess of about 200. Hard numbers welcome. 5 I should know. I own some of the cruft. 6 There were anywhere from 1 to 10 releases per library in that period. Some had multiple releases in the same day, a curious trend on CPAN. 7 Port a Perl module today! I should mention that I didn’t do any very long term trending, so I guess it’s possible that the releases per month have dropped, but I somehow doubt it. Feel free to prove me wrong (or right). 8Many thanks go to Tom Copeland for providing me with the RubyForge statistics. [Less]
Posted almost 19 years ago by Gregory Brown
This year is a good year for Ruby on the east coast. We kicked things off with a bang with the Gotham Ruby Conference in April, saw the Ruby Hoedown come and go in Raleigh bringing along with it some great videos of their talks, and of course, will ... [More] see the Seventh International RubyConf in Charlotte in just a couple months. However, these aren’t the only games in town. We’ve also got Ruby East 2007, which is a one day, multi-track, Rails friendly regional conference at the Penn State Great Valley Campus. They’ve managed to get an impressive list of speakers together, and even let two of those vagabonds from the Ruby Reports project sneak in to do their ranting. If you’re local to the area and don’t think you’ll make RubyConf this year, this is a good chance to still get your fix. If you’ve been tinkering with Ruport and want to shake down me or Mike, this is also a chance for that. From what I’ve seen so far, these regional Ruby conferences are always a lot of fun, especially because each one takes on its own unique flavor. If you want to go to this one, you should probably register soon because the event takes place on Friday, September 28, which is right around the corner. Hope to see you there! [Less]
Posted about 19 years ago by Gregory Brown
These days, it seems I hardly have the time for doing fun random hacks. So here I’ve started one, and if anyone finds it interesting, please take it from here and let me know how it turns out. Loosely based off of AIML, kind of, but not really: ... [More] class Conversation def initialize(person) @person = person @response_id = 0 end attr_reader :response_id def say(msg) print "#{@person}: " @response_id = Response[@response_id].respond_to(msg) end class Response def self.responses @responses ||= {} end def self.[](id) responses[id] end def initialize(id) @id = id self.class.responses[id] = self @matchers = [] @messages = [] end attr_reader :id,:matchers def when(pattern,id) @matchers << [pattern,id] end def inherits(arr) arr.each do |id| @matchers = Response[id].matchers end end def might_say(msg,weight=1) weight.times do @messages << msg end end def talk puts @messages.sort_by { rand }.pop end def respond_to(msg) @matchers.each do |pattern,id| if msg =~ pattern Response[id].talk return id end end return @id end end end def response(id) r = Conversation::Response[id] || Conversation::Response.new(id) yield(r) end [Less]
Posted about 19 years ago by Austin Ziegler
I’m looking for someone to take over PDF::Writer, color-tools, and Transaction::Simple. I do not have time to maintain these anymore. I should have done this months ago, but pride of ownership and a belief that more free time would be just around the ... [More] corner got in the way. You can read more details on my original blog posting at my personal blog. Anyone interested? Anyone know anyone interested? [Less]
Posted about 19 years ago by Gregory Brown
I think most Rubyists have picked up a good trick or two from Jim Weirich. Though it’s only a tiny part of his latest article (Using Flexmock to Test Computational Fluid Dynamics Code), I got excited to see his ‘Existence Test’ in his code: def ... [More] test_initial_conditions q = F3DQueue.new assert_not_nil q end Looks pretty simple, eh? You might be quick to say that this doesn’t do anything. However, its actually a pretty clever practice. This test makes sure the tests themselves are working as expected. I was already in the habit of starting with a failure, usually something like: def test_doomed flunk end The purpose of the above is simply to make sure your tests are picked up within your suite, and aren’t being overlooked by your Rakefile, autotest, or whatever runner you’re using. But the existence test actually goes a little farther. Because you’re initializing an object, you’re making sure that the files you need to be loading are present, that you can build your objects, *and* that your tests are hooked up. After you’ve got a couple tests passing, you can remove this sanity check or morph it into a setup(), whatever makes sense. Many people think this is a little paranoid, and most of the time, it is. Still, all it takes is one bad experience coding under falsely passing tests, and you’ll be converted in no time. :) [Less]
Posted about 19 years ago by Gregory Brown
This package is the most simple way to equip your Macintosh Apple OSX System with Ruby - similar to the Windows Ruby One-Click Installer. It replaces the broken Readline library, updates to a current version of SQLite3 and prepares your OSX for ... [More] Rails, which needs at least Ruby 1.8.4 to run. The current Ruby Version is 1.8.6 (1.8.5 is recommended for Rails) and Rubygems 0.9.4. This package’s intention is to remain small while being a Universal Binary that serves everything to deploy Ruby Applications on OSX Machines - Cheetah, Puma, Jaguar, Panther, Tiger or Leopard. You don’t need to compile anything and you don’t need Apple’s Developer Tools (xcode) installed. Some people use fink or other ports software, others (myself included) take the time to read through the HiveLogic post and do everything from scratch. Now there’s another option, and if it lives up to its claims, it should be A Good Thing. [Less]
Posted about 19 years ago by Gregory Brown
Well, our first ever spotlighted project has been selected. For June, it’s Sequel, the Concise ORM for Ruby. Development on this project has been like wildfire for the last couple months, with releases every few weeks. Support is available for ... [More] PostgresSQL, MySQL, SQLite3, and ODBC. There is also a wrapper for RubyDBI, which means that you can hook into pretty much any mainstream database if needed. Because code often speaks louder than words, we’ll take a look at Sharon’s proposal which won the June spotlight. The Proposal require 'rubygems' require 'sequel/sqlite' # gem install sequel (and sqlite3 as well) DB = Sequel.open 'sqlite:/' # memory DB DB.create_table :items do text :name decimal :price end items = DB[:items] 1000.times {|i| items << {:name => "item#{i}", :price => rand * 100}} puts "#{items.count} total items" puts "Average price: #{items.avg(:price)}" puts "3 most expensive items:" items.order(:price.DESC).limit(3).print(:name, :price) puts "#{items.filter {price < items.avg(:price)}.count} below the average" puts "Changing price for expensive items" items.filter {price > items.avg(:price)}.update(:price => 'price 10'.expr) puts "Highest price: #{items.max(:price)}" puts "Updated average price: #{items.avg(:price)}" Output: 1000 total items Average price: 51.9679610670265 3 most expensive items: ------- ---------------- |name |price | ------- ---------------- |item725|99.9570494326071| |item179|99.9012407557774| |item626|99.6490915522042| ------- ---------------- 478 below the average Changing price for expensive items Highest price: 109.957049432607 Updated average price: 57.1879610670265 As you can see, it is indeed pretty concise. Cool features - A little IRB wrapper that lets you load a database directly, a la sequel sqlite:///test.db - Sequel Datasets are Enumerable, but hit the database when the methods are called - Arbitrary SQL execution: DB << "create table t (a text, b text)" DB << "insert into t values ('a', 'b')" - Lots of ways to filter data: my_posts = posts.filter(:category => 'ruby', :author => 'david') my_posts = posts.filter(:stamp => (2.weeks.ago)..(1.week.ago)) my_posts = posts.filter(:category => ['ruby', 'postgres', 'linux']) my_posts = posts.filter {category == ['ruby', 'postgres', 'linux']} my_posts = posts.filter {stamp > 1.month.ago} my_posts = posts.filter(:category => /ruby/i) my_posts = posts.exclude(:category => /ruby/i) my_posts.each {|row| p row} posts.filter('(stamp < ?) AND (author <> ?)', 3.days.ago, author_name) That’s basically just what jumped right out at me, it looks like things go a whole lot deeper than that. Selfish Investigations I first gained interest in Sequel slightly before this contest started, as I thought it might jive nicely with Ruport. Turns out, that’s definitely the case. Here’s my naive hack that actually works for the simple cases: class Sequel::Dataset def report_table Table(:column_names => columns, :data => all) end end This lets you use Sequel for your data acquisition and Ruport for your formatting needs. irb(main):017:0> puts DB[:payr_employees].report_table --------------------------------------------------------------------------------------------- | lunch_hours | lunch_time | start_time | avg_hours | code | name | is_manager | id | --------------------------------------------------------------------------------------------- | 0 | 12:00 | 08:00 | 40 | gsgi | Gregory Gibson | true | 1 | | 1 | 13:00 | 11:00 | 30 | jon | Jon Juraschka | false | 2 | --------------------------------------------------------------------------------------------- => nil irb(main):018:0> puts DB[:payr_employees].filter(:code => "jon").report_table -------------------------------------------------------------------------------------------- | lunch_hours | lunch_time | start_time | avg_hours | code | name | is_manager | id | -------------------------------------------------------------------------------------------- | 1 | 13:00 | 11:00 | 30 | jon | Jon Juraschka | false | 2 | -------------------------------------------------------------------------------------------- => nil irb(main):019:0> puts DB[:payr_employees].report_table.to_csv lunch_hours,lunch_time,start_time,avg_hours,code,name,is_manager,id 0,12:00,08:00 ,40,gsgi,Gregory Gibson,true,1 1,13:00,11:00,30,jon,Jon Juraschka,false,2 Since Sequel::Dataset#all just returns an array of hashes, it was trivial to use with Ruport and I suspect that this structure is common in a lot of other Ruby libraries too, which means that Sequel offers a whole lot of shoehorn capabilities. Final Impressions I really like what I see here. It’s really a different feel than full blown ORM like ActiveRecord, and seems like it might be the ideal choice for quick and dirty SQL hackery. I definitely think that you could pick up the basics for this lib in 10-15 minutes and already have it be useful for you. The fact that the project is active and relatively new means there is room for growth and improvement. The API doesn’t feel incredibly polished, but for the most part, is fairly intuitive. I definitely think it’s a project to keep an eye on, and didn’t run into many problems with it while playing around with it. Hopefully, I’ll get a chance to work with it in some real projects soon. Sequel Community Resources Project Page API Documentation Mailing List The docs are halfway decent and the group has some posts worth checking out in the archive, for sure. June Spotlight Honorable Mention Though I felt like Sequel had the strongest proposal, the other ones I received were excellent. I’d like to offer an honorable mention for MenTal guY’s Omnibus Concurrency Library. The coolest thing in his proposal was Array#parallel_map which works like map, but concurrently. There was some other sick stuff in their too, so it’s worth checking out for sure. That’s all for this month. I’ll be accepting submissions for July until the end of the month. Until then, go give Sequel some love! [Less]
Posted about 19 years ago by GSoC Proxy
From Nick Sutterer, A Computer Science Undergraduate at Albert-Ludwigs University (Freiburg, Germany) When writing an article about Apotomo I had to make a decision: either introduce it as a simple widget plugin for rails or - as the name Apotomo ... [More] (”all power to the model”) implies - end up in monologues about model-driven component-oriented enterprize concepts. Today I will simply introduce Apotomo as a widget library for rails. Introduction Apotomo is a widget library for rails. The concept is familiar to everyone who’s already worked with a GUI library: Take a window, draw some frames in it and throw in some buttons. Attach some logic to the buttons, hook a method to the frame and you’re done. In Apotomo (that’s a widget library), the central place - where all this drawing and attaching happens - is the modeling tree. For your convenience I prepared a meaningful model which is the foundation of an imaginary drinking application: people can track their drinks in a database, can list what they drank and can view their current blood alcohol value. Useful? Not very. Example def drinking_model_tree top_page = page("Top Page!", 'top_page') track_page = section("Tracking Page", 'tracking_page') tracking_notebook = notebook('tracking_tabs') track_tab = tab("Track a Drink", 'track_tab') list_tab = tab("List tracked", 'list_tab') level_page = section("Permille Page", 'permille_page') top_page << cell(:drinker, :pages_menu, 'pages_menu') top_page << track_page track_page << tracking_notebook tracking_notebook << track_tab track_tab << cell(:drinker, :track_form, 'track_cell', :states => [:track_drink]) tracking_notebook << list_tab list_tab << cell(:drinker, :list_drinks, 'list_cell') top_page << level_page level_page << cell(:drinker, :show_level, 'show_level') return top_page end And a controller method: def apotomo act_as_widget('top_page', drinking_model_tree) end It may look a bit weird at first, but it is very simple: I nest widget objects to model my application. For example, I create a notebook widget which has two tab children, that again have children. Using the #act_as_widget method in a Controller action I can command Apotomo to render my top page. Have a look at the rendered states of the application! Can you see the cool tabs? This is all done by Apotomo since it provides some handy and ready-to-use widgets. We will now look at some of those widgets. Widgets? Apotomo (did I mention that this is a widget library for rails?) is based on another rails plugin called “rails cells”. A typical cell looks like a controller, with methods and respective views, but is not bound to a specific controller and thus can be called throughout the application. Every widget in Apotomo is a derived cell and can be fully adjusted to the developers needs - behaviour as well as the templates used for rendering can be overwritten. This is an important principle in Apotomo. Pages, sections, notebooks, and tabs are all structural widgets used for grouping parts of the application. They have predefined (but customizable!) views and behaviour. Notebooks and pages are very similar, they render themself and their current sub page/tab. Apotomo’s state- and addressing system provides information about which pages or tabs are presently focused by the user. The crucial parts of every application - the business logic - is packed into logic cells. Looking at our example app, the line list_tab << cell(:drinker, :list_drinks ...) attaches the #list_drinks method of the drinker cell class to the "Tracking Page" widget. This cell method could look like def list_drinks id = param(:user_id) @drinks = drinks_for_user_id(id) end This really looks common to us - it’s somehow identical to a controller method. But wait, what is this param() call? It’s more than a widget library! In conventional Rails parameter values are accessed using the #params method. Apotomo (Hey! Did you know that this is a widg… ok, I’ll be quiet) provides a more progressive approach to parameter accessing. Instead of looking directly in the global request parameter hash, a parameter request through the param method travels up the widget hierarchy asking every ascendent widget if it knows the value. This opens the way for a completely new parameter management and some innovative concepts which are already implemented in so called domain widgets in Apotomo. I’ll discuss this in the next article, promised! Another feature is the cell addressing in Apotomo. Normally in Rails you have to know the respective controller/method combination to address a specific function, e.g. when linking to another page, or in a form. We rather address widgets in Apotomo. Let’s take the line top_page << cell(:drinker, :pages_menu ...) that attaches the cell method pages_menu to the Top Page to render a clickable navigation menu. The view template for this method might look like <ul> <li><%= link_to_cell("Tracking Page", 'tracking_page') %></li> <li><%= link_to_cell("What's my level?", 'permille_page') %></li> </ul> That’s cool - we refer to cells (or, widgets) - and this brings some great advantage: the addressing mechanism travels - similar to the parameter thing - up the hierarchy and to the target cell, asking every cell on its way if they want add something to the address. This is extremely helpful for saving state-relevant information in urls. We’ll stick to this in the next article as well. Apotomo integration Basically Apotomo could control a complete application. However people will be sceptical with this new concept. The #act_as_widget method provides a way to render only parts of the modeling tree within views or controllers of an existing application. For example I could integrate only the tracking-notebook widget and its tabs in some view of my app - leaving it open to the developer how much “Apotomo” he wants. And now? This was a very brief overview about Apotomo, it has more features that will (hopefully) be discussed in another article. I’d love to see some discussion going on at http://nick.smt.de/trac/nick/wiki/ApotomoDiscussion . If you have any issues with Apotomo feel free to mail me at [email protected]. Props go out to Google for sponsoring Apotomo during Summer of Code 2007 and my mentor Patrick Hurley for his help and support! More about cells and Apotomo can be found at http://apotomo.rubyforge.org. The example app can be downloaded as standalone rails environment at http://rubyforge.org/projects/apotomo, but please notice that the API may change in the near future. [Less]
Posted about 19 years ago by Gregory Brown
Hey folks, I’ve picked a winner for June’s Ruby project spotlight and will have a post out within the next few days about it, but I’d like to remind folks that this is an ongoing project. What that means is that I’m now accepting July submissions. ... [More] Every submission we got for June was excellent, and if you were not selected, you can always resubmit for a later month. Here’s a recap of the rules, but see the original post for details. Project must be fresh / actively developed Project must be released before the time I post Proposal should consist of nothing more than a code example and a link to your project page, no additional commentary needed Project can’t be Rails-centric You must be a developer on the project My project choices will be entirely subjective and unjustified. :) Please email me if you’ve got a cool project to submit! [Less]
Posted about 19 years ago by Gregory Brown
To answer a question on RubyTalk the other day, I had to reference Mauricio Fernandez’s nicely compiled list of Changes in Ruby 1.9. While I was there I took another walk through the whole thing. There are of course some features I *don’t* like. ... [More] a = ->(b,c){ b c } a.call(1,2) # => 3 But there are quite a few that I do, and here I’ve listed ten I think will totally rock. I use Mauricio’s examples, so all credit goes to him. Also, this article is from February, so if you find any features below that have changed, shout and I’ll update. 1. Enumerator is in core and more tightly integrated This means all your enumerable objects can return Enumerators without a require, and also avoids some use of enum_for a = 4.times a = a.each a.inject{|s,x| s x} # => 6 I had to cross my eyes a couple times to understand what was going on there, but I came to the conclusion that ultimately, that is going to rock. 2. Enumerator#with_index I think most people will at some point be look to do a map_with_index, and this brings you quite close: [1,2,3,4,5,6].map.with_index {|x,i|[2,5].include?(i) ? x : x*2} #=> [2, 4, 3, 8, 10, 6] 3. Better Array#to_s and Hash#to_s [1,2,3,4].to_s # => "[1, 2, 3, 4]" {1,2,3,4}.to_s # => "{1=>2, 3=>4}" IIRC, puts will still do its magic when used on Arrays. 4. Method#receiver and Method#owner class A; def foo; end end a = A.new a.method(:foo).receiver # => #<A:0xa7c9f6d8> class A; def foo; end end a = A.new a.method(:foo).owner # => A I’m sure we’ll find something evil to do with that. :) 5. Process.daemon Process.daemon() => fixnum Process.daemon(nochdir=nil,noclose=nil) => fixnum By default, this will detach the process and change the working dir to the root. It’ll also redirect all output to /dev/null. Sounds like this will be a *nix only feature but having built in support for daemonizing scripts should be great. 6. Blocks can take block argument define_method(:foo){|&b| b.call(bar)} Hooray, a simultaneous win for higher order procedures and metaprogramming goodness! 7. Block arguments are always local a = 1 10.times{|a| } # !> shadowing outer local variable - a a # => 1 Compared to the nasty behaviour on 1.8: a = 1 10.times { |a| } a # => 9 8. New literal Hash syntax This is going to be great for making fake named arguments look even prettier { a: 1, b: 2 } is now equivalent to: { :a => 1, :b => 2 } which means you could easily do something like: foo(a: 1, b: 2) 9. Class variables not inherited Slightly weakening the case against them… 10. BasicObject A lot of times, you want a minimalist object. There have been plenty of hacks to show how to construct one in Ruby 1.8, but we’ll get one for free in 1.9 BasicObject.instance_methods # => ["__send__", "funcall", "__id__", "==", "send", "respond_to?", "equal?", "object_id"] Object.ancestors # => [Object, Kernel, BasicObject] Honorable Mentions Enumerable#group_by looks like it rocks. Symbol#to_proc wasn’t mentioned here but it’s handy (lets you do something.map(&:some_attr)). Also, the best damn Regex engine ever, Oniguruma, is built into Ruby 1.9 I wonder if the core team is still on schedule for a Christmas release…. Should be interesting to see how people make use of all this new stuff. [Less]