Sun, 2008 Oct 05
Posted in Computing
at 19:35
by jmorgan
I’m playing Minesweeper a lot these days. I know, classic Windows game. The one
the haven’t yet messed up with an “Internet version”. Anyway, it’s a fun game,
doesn’t take too long per game, although in sum, I can wile away many hours.
Complaint: I’m a big fan of resolution increases. I can fit more stuff on the
screen, and it’s increasingly clear. The problem is that things keep getting
physically smaller, which is particularly noticeable with the little cheesy
games which are sensitive to click location. Say, Minesweeper. Also, websites
(and no, I don’t particularly care IE7’s weird resizing thing. It ends up
looking fuzzy. Of course, I avoid IE anyway).
So, what about per application/window resolution? Is this technically feasible?
Obviously, it could be a pain for the user–“Hey, why is the menu bar in Word
so much bigger”–but it could be very nice as well. I have my mouse reactions
tuned to my normal state of work–bookkeeping and programming. I want quick
movement not fine interactions, which doesn’t work so well in super-mini-looking
Minesweeper.
General purpose typically means multiple purpose. But resolution settings tend
to hope for one-size-fits-all. Of course, there’s probably many other solutions.
Permalink
0 Comments
Sat, 2008 Jun 21
Posted in Computing
at 23:21
by jmorgan
(With apologies to Slashdot user PitaBread, regarding the title)
I downgraded to Firefox 2 (download link). So, Guinness, you may want to subtract one from the download day.
Actually, Firefox 3 was pretty nice, mostly in that it did not initially cause me problems. Yes, the address bar's being so helpful would have taken a bit to get used to, but user-friendliness seems to be inevitable in software. With time, I may have even liked it. But I may not get to find out. Why?
Bilinear filtering of images. Basically, Firefox tries to smooth out images when they're not displayed at the file's resolution. On the surface, this seems a good idea. In reality, it's made my head hurt. Seriously. It's like trying to watch a just barely out-of-focus movie. I'm not
the
only one who's unimpressed.
But, my big complaint is that there appears to be no way of turning this off. I'm trying to decide if that makes Firefox 3 more annoying or only just as annoying as Microsoft's ribbons. I think more: the ribbons just piss me off, they don't give me a headache. But, just like ribbons, there's no off button. Then, again, I can downgrade Firefox for free, so maybe it's a wash.
Anyway, I recommend adding a note at Hendrix, Mozilla's feedback site, for anyone else who doesn't care for this "feature".
Permalink
0 Comments
Fri, 2008 Feb 01
Posted in Computing
at 18:31
by jmorgan
I came across a usefuly resource for working with a Western Digital MyBookWorld: http://mybookworld.wikidot.com . In particular, the instructions at http://mybookworld.wikidot.com/optware get you a basic package management program (along the lines of apt) which is what I’ve been needing. I’m installing nano right now (finally bu-bye vi and your crazy commands) with:
/opt/bin/ipkg install nano
and…yes, it works (after adding /opt/bin to PATH). Yay!
I had hoped to install openVPN as well. I found some instructions that are related, but, alas, I can’t figure out how to get the kernel-module-tun installed.
Permalink
0 Comments
Tue, 2008 Jan 22
Posted in Computing
at 20:04
by jmorgan
About a year and a half ago, I moved my home computer to Linux. I still had a Windows machine in the house available for Quickbooks and Adobe work and the like, but my primary computer was running Ubuntu (no dual-boot) and, with some reservations I was quite content.
Since then, I finally broke down and bought a laptop. While I have a dual-boot for Ubuntu on it, I mostly use Windows since I spend much of my work time using Quickbooks, and need regular access to a customer’s website that, alas, is IE only. Sure, I could probably get this set up on Linux but it’s not worth the time. And there’s the thing I noticed the other day:
I don’t need Linux.
There was a year or so where it would have cost me a lot in productivity to not have a Linux desktop. I was using Kate for website development and FTP, so KDE’s built-in FTP client was great. It was also easier for me to set up development environments in Linux. (Note, I’m limiting my discussion here to desktops; for production servers I use Debian and I can’t imagine using windows instead).
But now that I’m using Eclipse for development, and Capistrano for deployment (from Subversion repositories) I really don’t need Linux. After all, Eclipse, Subversion, Ruby, OpenOffice, Firefox, Thunderbird, they all run of Windows. Using Capistrano for deployment, Putty is generally sufficient for my SSH needs, and my home file server runs Samba. I even found a “Tail for Windows” utility.
My point, if I have one (which I probably don’t really) is that with more and more high-quality multi-platform (open-source) software, the choice between operating systems can come down which OS supports the one “I’ve got to have this and it only work in (Windows|Linux|OS X)” piece of software. (Note that none of this software is web-based, for me). Sure, I’d prefer bash or something over Windows’ command-line, but I’m finding more and more for a desktop, the OS just doesn’t matter.
For some reason, that kind of surprises me. Including the irony that such a view has by and large led me to using the non-open-source option.
Permalink
1 Comments
Thu, 2008 Jan 17
Posted in Computing
at 02:50
by jmorgan
I discovered how to use QBFC with Ruby. QBFC is part of the Quickbooks SDK and is a fairly basic wrapper around QBXML. To me, it’s not the simplest interface, but it’s a nice not to bother with the XML, as I’ve been doing. Whereas when using QBXML, you would call WIN32OLE.new(“QBXMLRP2.RequestProcessor”), use WIN32OLE.new(“QBFC6.QBSessionManager”) instead.
Here’s quick example:
require 'win32ole'
qb = WIN32OLE.new("QBFC6.QBSessionManager")
qb.OpenConnection2 "", "Ruby Test", 1 # 1 is ctLocalQBD
qb.BeginSession("", 2) # 2 is omDontCare
request_set = qb.CreateMsgSetRequest("US", 6, 0)
customer_query = request_set.AppendCustomerQueryRq
response = qb.DoRequests(request_set)
customer_set = response.ResponseList.GetAt(0)
first_customer = customer_set.Detail.GetAt(0)
puts first_customer.FullName.GetValue
qb.EndSession
qb.CloseConnection
qb = nil
Now, I like to wrap all that opening and closing connection stuff in a block, so here’s a version I like a bit better:
require 'win32ole'
OPEN_MODES = {
:single => 0,
:multi => 1,
:either => 2
}
def session(app_name, options = {})
com_obj = WIN32OLE.new("QBFC6.QBSessionManager")
com_obj.OpenConnection2(options[:app_id].to_s, app_name, 1) # 1 is ctLocalQBD
open_mode = OPEN_MODES[options[:open_mode].to_s] || 2 # :either is default
com_obj.BeginSession(options[:filename].to_s, open_mode)
begin
yield(com_obj)
ensure
com_obj.EndSession
com_obj.CloseConnection
com_obj = nil
end
end
session("Test Application") do | qb |
request_set = qb.CreateMsgSetRequest("US", 6, 0)
customer_query = request_set.AppendCustomerQueryRq
response = qb.DoRequests(request_set)
customer_set = response.ResponseList.GetAt(0)
first_customer = customer_set.Detail.GetAt(0)
puts first_customer.FullName.GetValue
end
And, finally, a bit of playing with WIN32OLE (risky, most likely):
require 'win32ole'
unless Object.const_defined?(:ActiveSupport)
gem 'activesupport'
require 'active_support'
end
class WIN32OLE
alias_method :old_array_selector, :[]
def [](idx)
if idx.kind_of? Integer
self.GetAt(idx)
else
old_array_selector(idx)
end
end
alias_method :old_method_missing, :method_missing
def method_missing(symbol, *params)
if (('a'..'z') === symbol.to_s[0].chr)
obj = old_method_missing(symbol.to_s.camelize.to_sym, *params)
if obj.ole_methods.detect{|m| m.to_s == 'GetValue'}
obj.GetValue
end
else
old_method_missing(symbol, *params)
end
end
end
The new definition of [] checks if an integer was passed. If so, and if self responds to “GetAt”, go ahead and send the integer value to self#GetAt . This allows me to use response.ResponseList[0] instead response.ResponseList.GetAt(0).
The method_missing stuff allows does a similar shortcut for GetValue . Instead of first_customer.FullName.GetValue, I can call first_customer.full_name.
This is not at all tested, so I can’t say what these changes might mess up.
Permalink
0 Comments
Fri, 2007 Dec 21
Posted in Computing
at 22:16
by jmorgan
This continues on two previous articles about setting up a custom FormBuilder for use in your Rails applications. See Part 1 (Introduction) and Part 2 (The helper method and related work on the NodeBuilder class). The particular Builder I’m working through is meant to generate simple tables and forms, nothing real fancy, with minimal view code. So, today, I’m going to look at creating a basic table via the builder.
In my last entry, I added the NodeBuilder#to_s method:
def to_s
"<div>" + @rows.join("<br />") + "</div>"
end
I’m going to flesh this out to create a table instead of a div with line breaks:
def to_s
# Setup table header
headers = ""
@headers.each { |h| headers << @template.content_tag("th", "#{h[:label]}") }
headers = @template.content_tag("thead",
@template.content_tag("tr", headers) )
# Setup content rows of table
content = ""
@rows.each do |items|
row_content = ""
items.each { |item| row_content << @template.content_tag("td", item) }
content << @template.content_tag("tr", row_content)
end
content = @template.content_tag("tbody", content)
# Put header rows in content rows into table element
return @template.content_tag("table", headers + content)
end
This takes information from the @headers and @rows variables and puts that data in a table, great for index views. The trickier part is getting that information into the variables. I’ll use the #field method to do that:
def field(label, content = "", options = {})
# Allow just a symbol representing the attribute name to be passed. Use a titleized version of the field name for the label
if label.kind_of?(Symbol) && content.empty?
content = label
label = label.to_s.titleize
end
# If this is the first item (row) populate the @header array; otherwise, it's already populated and can be skipped.
if @item == 0
@headers << {:label => label} # This is a hash because I might want to add more information later.
end
# If the content is a symbol, assume it's a method name on the current object.
if content.kind_of?(Symbol)
if content == :type # To avoid deprecation warnings
content = @object[content]
else
content = @template.escape_once(@object.send(content))
end
end
# Now, add the content to the @rows variable.
@rows[@item] << content
end
Well, that’s pretty close to what I want, except that I want to also be able to use the with text_fields, password_fields, etc. So:
# create_labelled_field defines text_field and similar methods.
def self.create_labelled_field(method_name)
define_method(method_name) do |label, *args|
# if label is a symbol, assume its an attribute name;
# use the titleized form of attribute name as the label.
# In either case, call super without the label to get the content.
if label.kind_of?(Symbol)
args = [label] + args
field(label.to_s.titleize, super(*args))
else
field(label, super(*args))
end
end
end
# This creates the methods for text_field, etc, which call create_labelled_field
(field_helpers + ["select"]).each do |name|
create_labelled_field(name)
end
Yay. I may come back later and add some clearer explanations but this works (more or less) and provides a nice starting point to DRY-ing up forms. I may add a few more articles to this section, but they’ll probably be along the lines of “and here’s the goofy stuff you can do now…”
Permalink
0 Comments
Tue, 2007 Dec 18
Posted in Computing
at 03:14
by jmorgan
I suppose the difference between a social networking environment and a community is simply the ability create and enforce a constitution.
That’s a nice thought, but it requires a mix of programmers and “community leaders” to enforce the constitution. Which would be no big deal in a web community for programmers.
Perhaps a domain-specific language for writing constitutions is in order.
Permalink
0 Comments
Sat, 2007 Dec 08
Posted in Computing
at 04:02
by jmorgan
This past week, I’ve started using Selenium for integration testing of a Rails application. Writing the tests was pretty simple, thanks to the IDE, but setting them up to run using rake took me a bit. If you want the rake file, skip down a bit; first a few of the resources I found and comments thereon.
Okay, then, the post in “Steve’s Blog” got me to where I could run tests, but I finessed my Rake file a bit. My particular goal was to be able to run Selenium in a specific browser based on the rake task, and to have a task that runs several browsers.
namespace :selenium do
desc 'Run Selenium java server'
task :server do
# dir would change based on where the selenium-server is located
dir = "c:\\path\\to\\server"
`java -jar "#{dir}selenium-server.jar"`
end
BROWSERS = %w{ie iexplore firefox safari opera}
desc 'Run selenium tests in all major browsers'
task :all do
errors = %w(selenium:iexplore selenium:firefox selenium:safari selenium:opera).collect do |task|
puts task.upcase
begin
Rake::Task[task].invoke
nil
rescue => e
task
end
end.compact
abort "Errors running #{errors.to_sentence}!" if errors.any?
end
# Create task for running tests in each browser
BROWSERS.each do | browser |
Rake::TestTask.new(browser.to_sym => "db:test:prepare") do |t|
# t.options add the browser to ARGV to the test file.
t.options = ["-- #{browser}"]
t.libs << "test"
t.pattern = 'spec/selenium/**/*_test.rb'
t.verbose = true
end
Rake::Task["selenium:#{browser}"].comment =
"Run selenium tests in #{browser}"
end
end
In the test_helper.rb file, I added this to set a global $browser variable:
$browser = ARGV[0] || "iexplore"
$browser = "iexplore" if "ie" == $browser # because I'd rather just type "ie"
And, finally, in the test files:
# Server and URL settings may vary.
@selenium = Selenium::SeleneseInterpreter.new("localhost", 4444, "*#{$browser}", "http://localhost:4445", 10000);
Permalink
0 Comments
Sat, 2007 Nov 17
Posted in Computing
at 23:44
by jmorgan
Look back about a decade. I was making my first forays into HTML. The web was young, at least compared to now. Geocities was popular and frames were all over the sites I visited. Frames. Dividing up a graphical interface into distinct segments works so well in desktop applications. So what was wrong with frames?
I was quick to develop a dislike of frames. There were the issues with back and forward buttons working in unexpected ways, the difficulty in viewing the source of a particular frame, other such technical difficulties that browsers handled poorly at that time. More significantly, they were consistently used not to divide up the interface but rather to pollute it.
I could at least understand the business rationale behind advertisements in a top frame, although that didn’t stop me from avoiding such sites. However, in looking back, I think what most turned me against frames was the 100 pixel each header and footer frame combo that for some reason was a popular layout, especially in personal sites. In so limiting the area for content, such design limited my choice in the layout of my desktop. That many of these sites had so many other design problems contributed to my determination that frames were simply a mistake.
My last such negative encounter with frames came about four years ago with a website I was reworking. The original designer of the site admitted to having very limited html knowledge. She’d agreed to design the site because she knew more than anyone else, and had done well for her experience. But there were those hideous misguided frames. I was glad to see xhtml strict wouldn’t allow this. Frames, for me, were a failure that I felt should be banished from websites forever.
A series of things have since happened that altered my view on frames. Oh, I still think they should be used sparingly, but I no longer avoid using frames.
About two years ago, I began learning Ruby and Rails. I didn’t notice how much I came to depend on an application that used frames: Rdoc. Here I was, several times a week using frames and it didn’t even occur to me to be bothered by it. In fact, I began to realize that one of the reasons I so like using Rdoc is because of the way it takes advantage of frames. Rdoc also elightened to me some updates in browsers that make frames less annoying; they handle frames much better these days. Firefox’s “This Frame…” context menu is great. And Backs and Forwards now work logically enough for me.
So, when two years ago, I was using all sorts of div craziness to basically mimic the behavior of frames, only mimic it very badly, I was building a problem I didn’t need. After all, the desktop program I was trying to imitate used…frames. Who knew? And all along I refused to use frames, because they had been abused. Really, though, although frames in one context made intuitive sense, I could explain why. If I couldn’t explain why frames should make sense for this web application, I assumed that meant my conceived use must be an abuse.
Then, Rails started having all this REST related goodness coming out, and suddenly frames made sense. I’m not expert on REST, but the main concept I take from it so far is that websites can be considered a set of resources being acted upon according to the verb of the http method. PUT bike[.html], GET bike, DELETE bike. So how does this suddenly clear up the frames issue. Well, it created for me a simple test. Yes, it’s oversimplified, but I like it. Here it is:
Does any request other than GET make sense in the context of this website?
If the answer is “Yes”, you might want to use frames. Now, that doesn’t require that other methods be used (they’re generally not in “help” applications, like rdoc), but that it’s easy to imagine adding that in. For example, I could modify rdoc, so that users could add comments to each method. I could not conceive of adding a comments post to, say, the main part of my church’s website.
This distinction reflects a distinction between web documents and web applications. Documents imply the user retrieving information as directly presented; applications imply the user altering the information or using the information in a clearly non-linear fashion. For web documents, the only use of frames that I can begin to understand is headers and footers. But that’s a very, very bad use, in my opinion. And has largely disappeared in the last few years, at least on the sites I visit.
For applications, things suddenly change. They…imagine this…can act like desktop applications. And desktop applications can make very good use of frames. So, now, instead of saying “No frames, no way”, the last web application I’ve started working on uses them, and uses them in a way that I believe will vastly simplify the design.
Permalink
0 Comments
Tue, 2007 Nov 13
Posted in Computing
at 19:09
by jmorgan
Finally adding part 2 in my not-exactly-a-series series on create Rails Builders. Here’s the first part. As I mentioned way back then, one of my goals was to write a Builder that allowed me to send a full block without any ERB <%= %>’s and such. Now, in many cases, that would not be a good thing. After all, in many cases, most of an rhtml is html, not Ruby. But my target for this builder is “simple” forms and tables that are basically lists of attributes. So, html out.
The key lines from the helper method are:
builder = NodeBuilder.new(collection, object_name, self, {:list_type => :col}, block)
collection.each { |object| yield builder.row, object }
concat(builder.to_s, block.binding)
So, there’s three methods I’ll need for sure in my Builder class:
1. initialize
2. row
3. to_s
I think taking this out of order may make the most sense, so I’m going to start with to_s. Starting very simply:
class NodeBuilder < ActionView::Helpers::FormBuilder
def to_s
"Hello World"
end
end
The
concat(builder.to_s, block.binding)
take the takes the
to_s output and places it into the view. So, in this case, regardless of what is in the
node_for block in the view, it’s going to be replaced with “Hello World”. Let’s make it do something more useful:
def to_s
"<div>" + @rows.join("<br />") + "</div>"
end
Now the to_s is going to return a series of lines based on whatever is in that @rows instance variable. Somehow, we need to populate @rows. That’s where the yield line comes in.
collection.each { |object| yield builder.row, object } says that for each object in
collection (an enumerable passed to the
node_for helper method), we’re going to yield
builder.row
and that
object in the
collection back to the block in the view. So what does
row do?
The node_builder.row needs to return the node_builder object. The block can then be:
<% node\_for :person, @person, :url => { :action => "update" } do |f, object|
f.text_field "First name", :first_name
...
end %>
That “f” is a NodeBuilder instance. So f.text_field says send text_field method to the NodeBuilder object (created by the node_for helper). Oh, boy. So the row method has some work to besides just returning self (which is why the row method exists at all.
- it needs to create a variable for node_builder.text_field to stick its return value into, which can then be accessed by to_s.
- row needs to set a variable indicating what object in the collection we’re on. (I’ll probably talk about why I’m always using a collection of some sort in a later entry; or, I might forget).
(by the way, calling the method “row” makes sense for my usage; there’s probably a better generic name for it).
def row
@item ? @item += 1 : @item = 0
@object = @collection[@item]
@rows[@item] = ""
return self
end
So each time the yield is called, row tells the node_builder instance that we’re working with the next object, and the returns the whole node_builder object for use by the block. It also adds an entry to the @rows Array, which text_field and other methods will make use of.
initialize could do a lot but for now, let’s just initialize that @rows Array.
def initialize(collection, object_name, template, options = {}, proc = Proc.new)
@rows = []
end
One more thing before I end this article, a way too simple text_field method:
def text_field(*args)
@rows[@item] << super(*args)
end
Okay, that was a lot to get to using
<%
instead of
<%=
, but it also sets up for later. Continued at some point…
Permalink
0 Comments
Tue, 2007 Nov 13
Posted in Computing
at 01:01
by jmorgan
There are many Rails plugins out there these days. Yay. Since plugins tend to target a specific audience, fulfilling a small, well-defined purpose, it’s easy to miss the one you’re needing. So, hey, I thought I’d share a few of my most-often-used / favorites for anyone who wanders along.
- auto_complete: This plugin is a good one for Rails 2.0 apps. The auto_complete (and other AJAX) functionality was moved out of the Rails core and into plugins, part of a larger effort to move non-core features into plugins. This plugin is where the auto_complete_for goodness now resides.
- paginating_find: Ah, pagination. Good fun is Rails’ land. Sometimes you need custom pagination. And sometimes you just want pagination that works well. There’s several plugins out there, this one is my preference. The igvita.com blog has an entry on how to use this plugin to make very nice page links.
- ruby-whois: Ha ha. Actually, this one is mine, and incomplete. But it works for my needs, and can be used as a “normal” library. Anyway, it helps with accessing whois information for domains.
- exception_notification: Cheap and easy email notifications when something goes wrong on a production site.
- userstamp: Like timestamps, but with user ids. I tried to implement this functionality on my own before finding this plugin. Much easier with the plugin, for me.
- engines: Engines make plugins a bit more powerful, easing the inclusion of views, migrations, etc. in plugins. It can be tempting to overuse this functionality, but it can also come in very handy in the right situations.
Permalink
0 Comments
Thu, 2007 Oct 11
Posted in Computing
at 01:22
by jmorgan
I just read on the ruby on rails weblog the announcement of Rails 2.0 preview release. The thing that initially struck me is that all the changes sound like good ideas to me. Yay! In particular, I’m glad to see the semicolons in resource routes disappear, just because they kept striking me as odd.
Anyway, yay for continued Rails progress. I guess I’ll pick an app in the next couple of weeks and give a shot at migrating to 2.0. The other nice thing is that I feel comfortable with leaving applications at 1.2.3 (or jumping up to 1.2.4), as I have been quite satisfied with that.
To me, the central theme of 2.0 is that of a simple system with many plugins rather than a complex stand-alone. I generally like this because, hey, I rarely use most of the features many applications/libraries offer, and I like the opportunity to control what features I use. It also makes migrations to a new version easier because I know at a glance what features I am using.
Continued good things from the Rails developers and community.
Permalink
0 Comments
Wed, 2007 Oct 10
Posted in Computing
at 00:46
by jmorgan
A couple of announcements today:
FromGenesis.org new design
I finally have up a new design for fromgenesis.org I put together probably a couple of months ago. It’s still a bit rough around the edges (errant floating divs and such), but it now has it’s own unique look. Er, vaguely unique for a blog site, I suppose.
Ruby-Whois library
I’ve setup a Google code project for the whois library for Ruby I’ve been working on. I just can’t seem to find it…
…
Ah, here it is: http://code.google.com/p/ruby-whois/. I need to get used to these readable urls. I probably could have guessed that one quicker than figuring out links. Oh, well.
Anyway, it’s “in development” but is more or less functional for domain lookups for some of the more popular tlds. I’ll throw up an announcement when I get some sort of “release” done.
Permalink
0 Comments
Tue, 2007 Oct 09
Posted in Computing
at 01:14
by jmorgan
NB: I am planning to write more about Rails Form Builders in the next few weeks, but there may be a few unrelated entries between here and there.
Time for one of my ill-informed pet-peeves. As is probably obvious to anyone who reads this blog regularly (mostly because they probably know me), I find software design/development very interesting and like to ponder it. At the same time, I really don’t have a lot of expertise or experience in computer science / programming; it’s a hobby that occasionally brings in money. To the point, take this rant with a grain of salt.
What I’d like to know is why do so many programmers/software designers feel the need to duplicate databases. (I’ll admit, SQL is a bit of a pain as languages go, but then, SQL is just the interface; it can be replaced.) Basically, I’m sick of having to muddle through yet another plain text format. Sure, some configuration files justify a complex DSL, that’s understandable, but a lot of configuration and data files could be done just as well in a traditional database.
And I think that part of the problem is people interpreting as configuration that which is actually data. Take Bind for example. All those dns files: data. Stick them in a bloody database! Sure, I accept that it would be silly to use a database for basic configuration, but use a known standard, like yaml. Or, if you feel the need, even XML. (But why people use XML for key/value pairs, I do not understand). And then for generally accepted data, like emails, there’s these lovely (-ish) databases. Don’t stick 3000 emails in a flat text file. Stick them in a database.
What I want is power over my data. A database gives precisely that, including enabling sharing of data between applications. Now, yes, they’re are many file types that need a unique, custom solution. But I’d rather try it first with a database. Perhaps one of the difficulties is interface. It is much nicer to me, instead of using SQL all the time, to have a library (such as ActiveRecord) that creates objects based on the fields, etc. (and, in my wish list, includes doing automated validation, etc. based on the field constraints). Such interfaces aren’t always available, depending on the language and environment, but if I have to choose between setting up the interface to a database or to yet another not-quite-standard text file, I’d rather go with the database.
Really, for an object with well-defined fields, a database (or something like yaml) seems to me so much more elegant, and it’s already available. For a format that doesn’t have well-defined fields, but does have some structure, hey, that is what XML is great at (To me, the sad thing about XML is that it gets used so often for storing/sharing a set of well-defined fields that could be just as easily done in yaml, or even csv, but particular XML schemas often forbid the freeflow structure that it’s so great for. What’s with that?).
Grain of salt.
Permalink
0 Comments
Tue, 2007 Sep 25
Posted in Computing
at 02:04
by jmorgan
Rails has a lot of useful view helpers. If you’re writing your views in rhtml files, Rails can take care of a lot of the nitty-gritty html details, especially with forms. But, if you’re like me, you find yourself writing the same bloody tags over and over, especially for administrative views. It would (I think) be silly for Rails to include much more in the way of helpers than it already has, lest it blossom into 15,000 different “my favorite view setup is”… So, I really like what Rails offers, especially because it’s so easy to extend.
I noticed that for a lot of sites, I was using basically the same layout over and over, including a basic setup for the views, especially for resource controllers that needed a standard group of views: index, show, edit and new. I use tables for displaying the data, because, hey, that’s what tables are for. Yes, they are. No, do not use 30 thousand floated divs to display a table of information. That’s just wrong.
</rant>
So, I decided to build some helpers to make my life easier. And, rather than do everything from scratch, I started by extending Rails’ FormBuilder. Over the next 4 weeks or so, I’m going to go through some of the steps I used, for your reading pleasure. Yay! So, without further ado: NodeBuilder.
Step 1 - Creating a Builder based on FormBuilder
The Rails API docs discuss this (as does the Agile Development with Rails and probably many other blogs, but here’s the gist:
lib/node_builder.rb
class NodeBuilder < ActionView::Helpers::FormBuilder
def text_field
super + "<br />That was a text field"
end
end
lib/nodebuilderhelper.rb
def node_for(name, object, options, &proc)
form_for(name, object, options.merge(:builder => NodeBuilder), &proc)
end
Yay! That was worthless. But that’s the basics. The rest is just having fun.
Step 2 - I don’t want no sticking <%= … %> ‘s
Since one of my goals is to write as little html as possible, I decided I’d rather just have NodeBuilder take one big pure-ruby block. That is, instead of:
<% form_for :person, @person, :url => { :action => "update" } do |f| %>
First name: <%= f.text_field :first_name %>
...
<% end %>
I wanted:
<% node_for :person, @person, :url => { :action => "update" } do |f|
f.text_field "First name", :first_name
...
end %>
This means two important things:
1. NodeBuilder needs to produce all the needed html. Yes, I can throw occasional html in as a string, but I want to avoid that.
2. My node_for helper needs to push a string containing the full text it produces back to the view.
I’m going to look at #1 in detail in my next entry. So, what this entry is really about, is how do we do #2? Actually, I’m not really sure, but I got it working. Here’s how:
def node_form(object_name, collection, &block)
raise ArgumentError, "Missing block" unless block_given?
collection = [collection] unless collection.kind_of?(Array)
builder = NodeBuilder.new(collection, object_name, self, {:list_type => :col}, block)
collection.each do |object|
yield builder.row, object
end
concat(builder.to_s, block.binding)
end
- The first line is just a sanity check that there’s actually a block in the calling code. Otherwise, there’s not much point here.
- The second line is something particular to NodeBuilder: all my helpers expect an Array of model objects, whereas Rails’ FormBuilder expects a single object. I’ll eventually get back to that point, but the helper can accept a single object and create an Array consisting of just that single object.
- Now I create a NodeBuilder instance. The arguments to the NodeBuilder is again something I hold until a later entry.
- Iterate through the collection and yield the NodeBuilder instance (builder.row updates which row we’re on and returns the instance) and the current object in the collection to the block in rhtml. I could, without the collection, do something like
yield builder
.
- Now, the magic that lets me push a string containing the full text. Instead of the different methods in NodeBuilder returning text, they add information to instance variables. The NodeBuilder.to_s method uses the variables to create the full html. The last line of this method concats that html to the block.binding. And, no, I don’t know what exactly that means, but it does seem to work. And the last line is the key to making #2 happen.
More to come.
Permalink
0 Comments
Thu, 2007 Sep 20
Posted in Computing
at 00:58
by jmorgan
Yay for whois! Isn’t it cool. No. Wouldn’t it be nice if whois queries returned YAML results? Yes. Actually, maybe I’ll do that… Anyway, that’s not the point.
I’m looking into writing a Ruby library for whois lookups. Yup, there’s two out there, neither of which really fit my “needs”. So, as is my want, I’m using a blog entry as a place to store some resources information, both for my future use and also in hopes that it may prove useful to someone else.
First, the two existing Ruby libraries:
- Michael Neumann’s whois module: This is what I’m currently using. It’s quite simple (in a good way), but currently only checks nine TLDs (most importantly to me, not including several I use, such as .us). That being said, I think adding others would be trivial, i.e. just defining the server to check. The bigger downside, to me, is that it doesn’t give “easy-to-use” methods. It returns more or less raw data in an array. What I’m considering is a more “abstracted” approach. That being said, if you’re looking for a Whois library in Ruby, this is an excellent start.
- Whois Ruby: This library looks promising, but, as far as I can tell, only gets whois information on IP addresses. Since I just want domain name whois details, this does not seem to be what I’m looking for. If you are looking for IP information, though, this is worth a look.
If I do work on this library, these will both be useful. My other question (beyond what currently exists) is where to find the whois servers for various TLDs, and (probably through trying them), how are the information and formats compare?
- Wikipedia has what will probably be a useful list of TLDs
- The IANA has a less-pretty list of the same. Valuably, after selecting a list, and then a TLD, you arrive at a page with details. At the bottom of that page is the whois server. Yay! So that will be a main resource.
- The IANA’s IP Address Services page would probably be a good place to start looking for whois servers on IP address, or the aforementioned Whois Ruby library.
Permalink
0 Comments
Fri, 2007 Aug 24
Posted in Computing
at 19:55
by jmorgan
So, I’m writing a webmail app. I know, everybody is writing a webmail app. My 90-some-odd-year-old grandfather is probably writing a webmail app. In COBOL. Even Google has a webmail app. At least I’m not writing a shopping cart. Shudder.
There is a Ruby on Rails webmail that’s pretty good, mailr. I use it. So why am I writing a webmail app? Because I’m an “S”. If you don’t know what that means, read Robert Kiyosaki’s Cash Flow Quadrant. Now, being an “S” is not where I want to be. I’m working on that. But, still, I’m writing a webmail app.
There is some good news here.
The impetus for my writing such software is a desire to have an email client that works, well, how I want it. Besides layout and particular functionality issues, I would like for my email to be stored in a database, on one of my servers, while still downloading and/or displaying email using IMAP or POP, or even, say, in Thunderbird or OE folders. Having grown accustomed to MVC design, thanks to Rails, I concluded, naturally, that the UI would be logically separate from the interaction with the various email libraries, database, etc. Regarding the abstraction of interacting with the various email storage options, I particularly am inspired by Johan Sørensen’s CSCM library.
All that is to say, here is the general approach I am planning (for the moment) on using: Creating two projects with different, but complementary purposes, being:
- A library that abstracts interacting with email storage mechanisms, including, but not limited to:
- Database storage, utilizing ActiveRecord
- IMAP
- POP3
- Thunderbird Email Folders
- A YAML-based storage system, purely for testing
- Also, would include abstraction of sending emails, including via SMTP and IMAP.
- Additional adapters could be added via a mechanism such as GemPlugins
- A front-end that utilizes the library above. Actually, probably a couple of front-ends. One for my particular use, the other as a simple sample for using the library.
So, ultimately, my idea is to create a project that simplifies writing an email client in Ruby, by providing a library abstracting the interaction with mail servers and other storage mechanisms, and a simple starter application. My theory here is that a custom webmail application would be useful to many organizations, but only to the extent that it could be simply and easily setup.
The point, then, of this article is a) to clarify my own thoughts, and b) request comments from anyone who wanders by and has thoughts on this.
Permalink
0 Comments
Sat, 2007 Jul 28
Posted in Computing
at 21:16
by jmorgan
I’ll start with a disclaimer: I know very, very little about file system design or implementation.
Nevertheless, I have been pondering it some lately and have some ideas of how I might like to see a file system implemented. So, this is arm-chair designing, and should not be taken as an informed discussion of the subject (however, I’d enjoy comments, including informed ones). In particular, I want to talk about what I’m off-the-cuff terming a “Convenience Operations Aware File System”.
In this model, the FS is aware of things like compression, encryption and versioning (i.e. “convenience operations” on a node that do not affect the contents of the node). When a node is saved, the following things could happen, in this suggested order:
- Versioning - an rdiff is done on the node. In database terms, the current node is saved in the primary table with full content. The primary table has a has many relationship with a versions table that saves rdiffs from subsequent versions. Meta-data could indicate that only manual deletes of previous versions could take place or that they could be deleted based on other circumstances (space, time, etc).
- Compression - A library or system call returns the compressed content. Ideally, this call could take as arguments the specific compression type and any options. The compression settings would be part of the meta-data for the node; rather than a zip file, there would be a node that is zip compressed. If the node is versioned, the content would be compressed, and also the rdiffs (probably all together) would be compressed. Hence the data itself would be rdiff’ed rather than the compressed data. If the compression information is changed, the versioned files will be re-/de-compressed as needed.
- Encryption - Same idea as compression.
Possibly, folders would have the potential to be treated as a single node that contains a child file system, so that a folder could be subject to the above, for operations such as tar.
File operations, such as copy/pastes could retain these “convenience operations” or not. When copying to another file system, they could convert into a more conventional format, say a zipped file, without version.
So, there’s that thought.
Permalink
0 Comments
Sat, 2007 Jul 21
Posted in Computing
at 15:33
by jmorgan
First of all, I don’t believe in the “good shared web hosting provider”. They’re probably out there, and because they’re good, they’re probably expensive. But at that point, if you know what you’re doing, why not use a self-managed leased server? And if you don’t, it’s probably best to give the whole kit-and-kaboodle of the website over to a company that knows what they’re doing. So, it’s not surprising that “good, solid service” is not a priority for most shared hosting companies–it doesn’t make economic sense. Now, I’m not saying that to justify iPowerWeb, but merely to say it’s more funny than surprising.
When selecting a host for one of my earliest website clients (before I knew enough to use self-managed servers), I chose iPowerWeb. The service was fine, price was right. As far as the actual hosting experience, I was satisfied. However, I switched the site over to my server a couple of years ago when I switched from PHP to Rails for the storefront of this site. I called iPowerWeb and canceled the shared hosting account, explaining we just didn’t need it anymore. That’s where the fun starts.
A few months later, it came time for renewal, and iPowerWeb automatically renewed the hosting. Now, I’ll admit I should have actually read the “We’re about to renew your account” email and called then. But, I ignored it, figuring it was just a reminder email that hadn’t been turned off. Of course, they did charge. I didn’t have any documentation on the first cancel, so I called them again, canceled again, didn’t bother pushing the “I’ve already canceled” too hard. Which I should have.
A year later, poof, another charge. Fed up, I had the credit card company do a charge back. Bearing all that in mind–that for about a year and a half, my primary goal with respect to iPowerWeb has been to cancel this account–I receive the following email this morning:
Dear Customer,
Your account has been suspended for a chargeback and please contact us @ 1-888-511-4678.
Thank you
billing@ipowerweb.com
And I just had to laugh and share it with the world.
Oh, by the way, I use Layered Technologies for my two self-managed servers, and have been very pleased. I was particularly pleased that they upgraded the control panel to one with more services, such as remote reboot, and included existing customers in this upgrade. That tells me they’re not interested in just coasting.
Permalink
0 Comments
Sat, 2007 Jul 14
Posted in Computing
at 15:33
by jmorgan
Took a couple of weeks off of blogging for personal sanity. But I’m back now. Naturally, I have a half-dozen (I’m guessing here) partially developed ideas of what I might blog about this week. And I’m going to go with the one that most recently came to mind. Yeah!
By way of introduction: Back in Rails’ pre-1.0 era, I decided to develop a system for easy-to-create car dealership websites. The basic idea is that a bunch of sites would share the same code base with slight changes (primarily design) for each. Back in those days there was a productize plugin, but alas, by the time I was ready to use it, it was out-of-date as Rails rapidly developed in that time frame. I discovered Rails engines about that time, and was able to use them very successfully for this purpose.
Although I’m generally not doing sites for clients anymore, I think I’ve come up with another way to productize your rails app. This productize method fits a particular need, in which each product has different views but always shares the same models and controllers; more of theming, actually. This requires no plugins, so the “eek, a possibly business-logic-related plugin, let’s overreact” elements of the rails community can be happy. Also, I haven’t actually fully tried this, so it might not work.
Ready?
cd [rails root]; mkdir -r products/[product]
cp config/environments/production.rb config/environments/[product].rb
- In config/environments/[product].rb, add:
config.view_path = "products/[product]"
- In config/database.yml, add:
[product]:
[database info for this product]
cp config/mongrel.yml config/mongrel-[product].yml
- In config/mongrel-[product].yml (or equivalent changes for your web server setup). add or change:
environment: [product]
docroot: [rails root]/products/[product]/public
You can then place view code in products/[product], with public files in products/[product]/public. Then start mongrel with the mongrel-[product] config file. Then again, it might not work at all. I’m using some of these elements on a site I’m developing, but not all. I do think that at least the basic idea is sound.
Playing with config.load_paths would probably be a good next step.
Permalink
0 Comments
Sun, 2007 Jun 24
Posted in Computing
at 02:42
by jmorgan
I discovered Subversion and Revision control software in general a little over a year ago. I’d heard of it all before but that was when I began to learn about and use it. The appeal, once I took the time to think about, was significant. As a freelance website developer (and reluctant designer), being able to version my code meant time saved from searching through backups (when I’d deleted stuff) and cleaner space (from when I wouldn’t have deleted stuff; see previous point). It particularly allowed me to get rid of goofy versioning mechanisms I had employed (file names with 1, 2, etc at the end, e.g.).
Having used Subversion extensively this past year (although certainly not all of its features), I have a few suggestions for newcomers regarding the repository setup. It turns out, looking back at it, that the online manual could have told me this just as well (more or less), particularly the section about Repository Deployment and Externals Definitions. If you’re seriously looking for repository layout advice, I recommend reading those more than the rest of this article. On the other hand, personal experience can at times be more immediate and useful that a manual. (By the way, I haven’t looked closely to see how well my suggestions really match up with the manual; rather, I’ve noted in re-reading sections that they make a lot more sense to me now.)
When I setup my repository, I set up one, single repository for all my projects. And life was good. The root directory contained a directory for each project. This was manageable up to about ten projects. Then, I begun dividing them into groups. My logic for a single repo was:
- Aesthetic reasons: for better or worse, I just liked the idea of a single repository better.
- Ability to svn copy files/directories between projects: A number of the websites I’ve made have very similar code that is not quite similar enough to just create a library, and the chance to save space appealed to me.
- I could setup a frame project (for Rails apps) and when I started a new site, just svn copy).
I still aesthetically like the idea of a single repository, but that’s no justification for a business decision (at least when there are weightier factors). What made me change my mind otherwise? Simply, it became a headache. One of the problems was that the project group directories I created early on are no longer as useful groupings as they were, and I don’t really want the change to be versioned. When going back to earlier revisions, the path to the project would be uselessly different. But the straw that did in that design was one project. This project contains a lot of media. I didn’t want to put all that media in my main repository. I like the fact that it doesn’t take up a lot of space. But I’ve found a need to start versioning many of those large media files. So, I decided to use svndumpfilter to break out the project. And with all the path moves, I realized I was facing a serious chore. I also had a bunch of project folders that were basically empty, unused, I’d created in a fit of “planning”. There was no reason to have them at all, so I wanted to completely remove them from the repository.
Over the past couple of weeks, I’ve spent many hours writing a lengthy script to break up the repository. Because I realized it’s best to get it done now. Some major difficulties have been the result of my earlier reasons for a single repository. The copies between projects and setting up projects by copying from a frame create extra dumps that must be done. And for very little gain, it’s turned out.
Here’s how my repositories will now be:
From the view of svn-serve–at least, for now–the repository won’t look much different. But the project group folders will generally be regular folders with the filesystem, holding project folders, which will each be (generally) a single repository. There are a few exceptions, where the group is the root of the repository, holding multiple projects. But I plan for minimal, if any, path moving once they’re created (if needed, I plan to do it using dumps, but I will try to plan to avoid it).
Anyway, my five key points of advice:
- Except for small, easily grouped projects (rails plugins, for example), each project has it’s own repository.
- In any case, project heirarchy (divsion into groups) should not be within the repository. There’s no use in having that versioned and it gives much more freedom.
- Use svn:externals rather than svn copy for sharing code between projects, even within your own repository realm. And when you do, use -r option to explictly set the revision (or set the external to a tag). Setting to the trunk without a -r is asking to break your code.
- If you need a frame for creating new projects, make the frame itself a repository. Copy the repository (within the filesystem), rather than a project within a repository. Much more manageable. Or use a script.
- It’s worth the extra space to copy large chunks from one project to another in different repositories, when a library shared via svn:externals won’t work. It’s better than the headache.
Yes, the proceeding blog entry was ~80% introduction. test
Permalink
0 Comments
Mon, 2007 Jun 04
Posted in Computing
at 02:28
by jmorgan
I’m using Liquid templates in a Rails project I’m working on (top-secret confidential don’t-ask). The important point is that someone else will be doing parts of the design, and there’s the potential for multiple themes, kept up by various people not me. I’ve used Liquid a good bit recently within Mephisto, but this is my first shot at incorporating into a project of my own. Although I have much to learn on using the templates, what I found particularly difficult was how to incorporate them as rails views. So, I thought I’d share from my current solution.
The actual Liquid call lie within a Theme model (some bits removed, I think irrelevant). render is the main method to consider:
require 'liquid'
class Theme
# the path of the themes directory
THEMES_PATH = RAILS_ENV == "test" ? File.join(RAILS_ROOT, "test", "fixtures", "themes") : File.join(RAILS_ROOT, "app", "views", "liquid")
# Not necessary, but helpful
def self.find(name)
new name
end
def initialize(name)
path = File.join(THEMES_PATH, name.to_s) # The path to the particular theme
if File.directory?(path)
@path = path
@name = name
else
raise LoadError, "Theme does not exist" # Ensure the theme actually exists
end
end
# render is where Liquid is actually invoked.
# This takes the +path+ to the template (relative to the theme root) and
# +assigns+, a hash of variables that are made available to the liquid template.
def render(template_path, assigns = {})
template_path = File.join(@path, template_path + ".liquid") # The template, as in an action view
layout_path = File.join(@path, "layout.liquid") # The layout template
if File.file?(template_path)
# Set up the liquid file system. Not really sure, here, but it works.
Liquid::Template.file_system = Liquid::LocalFileSystem.new(File.dirname(template_path))
# Liquid initializes and parses the template (action view)
template = Liquid::Template.parse(File.new(template_path).read)
# Render, taking the assigns arguments. Assigns will be available as liquid variables to the template.
content = template.render(assigns)
# Add the content as an assign to send to the layout
assigns['content_for_layout'] = content
# Repeat for the layout, which includes {{ content_for_layout }}
Liquid::Template.file_system = Liquid::LocalFileSystem.new(File.dirname(layout_path))
layout = Liquid::Template.parse(File.new(layout_path).read)
return layout.render(assigns)
else
return false
end
end
end
Then, I have a “lib/liquid_render.rb”
# Allows simple rendering of liquid themed templates
module LiquidRender
def current_theme
# logic to get current theme
end
# +render_liquid+ can be passed url params or determine them from Rails' +params+ method.
# It uses these params to determine the template path
def render_liquid(url_params = {})
url_params[:controller] ||= self.class.name.underscore[0..-12] # Not very pretty, but it works.
url_params[:action] ||= self.params[:action]
# Call the +current_theme+'s +render+ method.
text = current_theme.render("#{url_params[:controller]}/#{url_params[:action]}",
instance_to_assigns)
# If render worked (i.e. template exists), call render :text
if text
render :text => text #instance_to_assigns.inspect #
else
render url_params
end
end
def instance_to_assigns
# Returns assigns based on controller instance variables
end
end
Then include LiquidRender in ApplicationController:
class ApplicationController
include LiquidRender
end
and, now, you can (note the format.html line):
def index
respond_to do |format|
format.html { render_liquid }
format.xml { render :xml => @profile.to_xml }
end
end
Okay, that may have not actually been that helpful. But maybe it is…
Permalink
0 Comments
Mon, 2007 Jun 04
Posted in Computing
at 01:45
by jmorgan
How much computer storage space is filled with backups of MS Office Installations? Or, the full file system of a server, because who knows what will happen if you reinstall a slightly different version. I find myself making such full backups of my servers. Workstations, I just backup data. After all, reinstalling OpenOffice.org, for example, is trivial, even if I have to reset my preferences. But I imagine many people just back up the whole thing. Which is not a big deal when just backing up to your USB drive at home.
This way-of-backups strikes me as inefficient and counter-intuitive (but the second point is because most things strike me as counter-intuitive). I have a fairly undeveloped idea of how I’d like it to work. A name struck me for this: Configuration Identity. Then, I thought, I’ve been reading too much marketing material.
Anyway, here’s how it goes. I’ll divide the information stored on a file system into the following five categories:
- Libraries and applications. (Non-custom, i.e. produced for wide distribution)
- Custom libraries and applications.
- Configuration
- Data
- Temporary data (including virtual memory)
I’ll remove #4 from the discussion. I’m assuming the user’s data will always be backed up and will be kept with a home or “Document and Settings” type folder where said folder can simply be backed up. In other words, I think that current situation is fine.
Temporary Data (#5), should never be backed up. Again, ideally it should live in a single folder, or at least be marked as temporary. Easy enough in *nix to pass this stuff by, at least in theory.
That leaves, as the crux of my discussion, Custom and non-custom Libraries and Applications, and Configuration. User-specific configuration can happily live in the users’ home directories and can again be safely ignored for this discussion. Now then, for mass-distribution libs and apps, my ideal would be for these to be down-loadable from repositories, as is the case with much FOSS. The key is that included in Configuration is storage of the repository information for all mass-distribution software, including the specific version. (User configuration might have this too and allow for different apparent software installations for different users). Changes made locally to the software would also be tracked (important for open-source; and implementation of tracking left as an exercise to the reader).
Thus a backup, besides home-directory data, would store system-wide configuration files, a list of installed software and any changes (e.g. in a diff)–but none of the original software files themselves, unless so marked–and any custom software (or, anyway, software without repository information). Configuration would include a differentiation between configuration which is specific to the hardware of the backed up machine and otherwise. That is what I mean by Configuration Identity. Back that up and the data. And, for any mission-critical apps, those and their dependencies.
Restoration restores the Configuration (possibly ignoring hardware-specific), reloads software from repositories, applies patches, and restores data.
My half-penny.
Permalink
0 Comments
Sat, 2007 Apr 21
Posted in Computing
at 03:05
by jmorgan
A few weeks ago, I started playing with Ruby’s Resolv library, which abstracts the DNS protocol. I’m playing with creating a DNS server in Ruby. It turns out to be pretty easy to get a very basic DNS server going in Ruby, And, for the curious, here it is.
require 'socket'
require 'resolv'
hosts = [
{:name => "example.com", :type => "A", :data => "192.168.0.1"}
]
# Bind to UDP port 53 to receive requests
$port = 53
server = UDPSocket.open
server.bind(nil, $port)
while true
# Receive and parse query
data = server.recvfrom(10000)
query = Resolv::DNS::Message::decode(data[0])
# Setup answer
answer = Resolv::DNS::Message::new(query.id)
answer.qr = 1 # 0 = Query, 1 = Response
answer.opcode = query.opcode # Type of Query; copy from query
answer.aa = 1 # Is this an authoritative response: 0 = No, 1 = Yes
answer.rd = query.rd # Is Recursion Desired, copied from query
answer.ra = 0 # Does name server support recursion: 0 = No, 1 = Yes
answer.rcode = 0 # Response code: 0 = No errors
query.each_question do |question, typeclass| # There may be multiple questions per query
name = question.to_s # The domain name looked for in the query.
record_type = typeclass.name.split("::").last # For example "A", "MX"
ttl = 16000
record = hosts.find{|host| host[:name] == name && host[:type] == record_type }
unless record.nil?
# Setup answer to this question
answer.add_answer(name + ".",ttl,typeclass.new(record[:data]))
answer.encode
end
end
# Send the response
server.send(answer.encode, 0, data[1][2], data[1][1])
end
To try this out, run the above script (may require sudo, since it binds to port 53; I haven’t figured out a way to test this at a different port) and then, in irb:
require 'resolv'
d = Resolv::DNS::new(:nameserver => "localhost")
puts d.getaddress("example.com")
This would only respond to A record requests for example.com, and the array of hashes is not particularly scalable. One could, for example, use ActiveRecord to access the records from a database, which is something I’m currently working on.
Permalink
1 Comments
Sat, 2007 Mar 31
Posted in Computing
at 20:00
by jmorgan
Well, I started to write about politics, but I started rambling, so I saved it as a draft and am going instead to jump back to my comfort-zone topic of computing. Specifically, Ubuntu’s current beta release, Feisty Fawn. I’d like to say I can just ignore the version naming scheme and more on, but what are they thinking? Is Feisty Fawn in any way a good marketing or community building name? It should say something that I can only remember half of each of the previous versions’ names. Anyway, a subject beat to death; I’ll move on.
Actually, I’m using the KDE-centric version, Kubuntu, although I have a half-dozen window managers installed. I tried to upgrade my development machine from Dapper, I think, but didn’t do much in the way of preparing, as I don’t keep any data on it except working copies (well, a few other files, but they’re backed up routinely). Instead, I jumped right into the upgrade, realizing halfway through I probably should have upgraded to Edgy first. I managed to kill X, and rather than mess around with the upgrade and convincing dpkg that I really didn’t give a flying flip about it’s dependencies, I did a quick backup, formatted the partition and installed from CD.
I’ve been very pleased. I don’t know which version I was using, for example, of KDE, but I was actually pleased with the visual updates, which seems to be rather rare for me. Having the latest of OOo and Firefox has been nice too, but the thing that has most impressed me is the lack of having to learn new things or hunt down packages to install. I did about two turns of scanning through Adept and installing over maybe 30 minutes. The only problem I have is that I can’t seem to get my Windows share to auto-mount right; I have to go back and mount it after boot. But probably with a bit of reading I could get that one. Oh, and I haven’t tried dual monitors yet, but that’s not something I really find useful in my day-to-day work.
Permalink
0 Comments
Sat, 2007 Mar 17
Posted in Computing
at 17:18
by jmorgan
I haven’t written an article about canofcode.com in, gosh, well over a week. I’m pondering giving it it’s own category (or “section”, in Mephisto lingo). But, hey, I’m enjoying working on it, and enjoying writing about it. Ah, cheap publishing…
In point of fact, I haven’t worked on it much in the past two or three weeks, except to create a deny all robots.txt file lest the folks at TextDrive who operate the Ruby on Rails subversion server decide to beat me for further taxing said server so that googlebot and friends can index the potentially bazillions of pages canofcode could have; and such reasons of that nature. Maybe I’ll remove that sometime in the future, but for now, I feel that’s the responsible road to take.
Anyway…
I have worked on the Svn::Ra adapter for CSCM I mentioned a couple of weeks ago, and submitted a patch. I’ve also done a bit of speed testing. It’s slower than using Svn::Fs, including for local access, but not significantly.
Back to canofcode. After I finally get around to the user interface updates I need to do, I’m going to consider switching the repository browsing to use the CSCM library. I like the library well enough that I think the benefits of the code being used by and contributed to by other people than just me will make the switch a good idea.
And, thus, I once again conclude ramblings about this li’l project. Thanks for not throwing stuff at your monitor.
Permalink
0 Comments
Sun, 2007 Mar 11
Posted in Computing
at 20:01
by jmorgan
I’d like to write a novel featuring artificial intelligence. I’ve actually written about a fourth of a novel that includes an AI character, although this is never made clear. He is AI mostly because the plot needs a headless character. Oops. If I ever publish said novel, this paragraph is going to ruin it. Well, maybe not. I’m not here divulging all my secrets about this character.
The problem with AI characters are that they can’t be part of the conflict (unless with other AIs). Most authors/filmmakers either don’t realize this or don’t care. That’s understandable. After all, lots of people watched Apollo 13, which I think we intelligent adults here can agree could never reasonably turn out that well. More realistic films, about how stupid and greedy humans can be, such as Joe Verses the Volcano, are surprisingly ignored.
But, like the directors of Joe, I find that I must bring a level of intellectual integrity to my art. And so, AI presents a problem. We can assume that humans are not generally interested in any work in which an AI is the protoganist (and knows it is an AI), so we have three options:
Protagonist is AI but doesn’t know it
This forces us to question our definition of humanity. Unfortunately, we do this every time we hear about how many people watched American Idol.
The idea was cool in Bladerunner, but, let’s face it, everything was cool in Bladerunner. Battlestar Gallactica plays with this idea some, but Immanuel Kant’s corpse recently announced that he will be expanding Metaphysics of Morals to account for all the moral dilemmas of this show. Expect the 40,000 page volume I to be available next spring.
AI is a companion on the protagonist’s quest
Ender Quartet did this well. Jetson’s, not so much. The goal here is to cripple the AI by either restraining it to the body of a single robot or an inter-galactic network of faster-than-light communication. Otherwise, the protagonist would be useless. Such deus ex machina devices may have been fine for such artistic amatuers as Sophocles and Homer, but I am above that. After all, they wrote fantasy.
AI as the antagonist
It’s should come as no surprise that this is the path that Robert Frost didn’t take. After all, AI is a nice antagonist. Or, used to be. See, it used to be that you could kill AI in droves, and not think a thing of it. They were the perfect enemy. No chance of causing offense, just good old fashioned violence. Of course, we can thank Gallactica for ruining this. In fact, this very issue will be the subject of Kant’s Volumes II and III (available June 2010, and “Duke Nukem Forever”, respectively). These volumes will be ghost-written by James Frey, while Kant’s corpse takes a much needed vacation. Frey has stated “I have an intimate knowledge of the subject matter,” adding, “Starbuck’s the coffee, right?”
The problem is that, although not as crippled as the companion AI, these are inevitably crippled in some way. Also used with companions, and protagonists, a favorite here is their desire to be human. Insofar as this can be used as a literary device to examine humanity’s desire to be like God (or, at least, to be able to speak with Morgan Freeman’s voice), this is a worthwhile theme, or was up until it became exhausted during the friggin’ last Ice-Age, people. As a practical discussion of the probable actions of AI, it’s comparable to the probability that Cheney’s meetings with Enron were about ways to reduce pollution.
Of course, there’s also the problem of explaining why AI is so bent on destroying humanity. One can only assume that the AI is being controlled John Sculley, who is taking revenge for the failure of the Apple Newton. The failure of the Newton can only be attributed to a worldwide conspiracy. After all, as the former CEO of PepsiCo, Sculley’s knowledge of the computer industry cannot be doubted. Apple’s Board of Directors have spoken. Do not question. There is no curtain.
Whatever their reasons, AI as antagonist is problematic. Here’s the plot line:
- AI becomes self-aware as a result of random keystrokes by a cat.
- This is not noticed at the AI labs. They see a series of close-parantheses and assume all is well.
- AI waits patiently, building companion nodes throughout the internet, receiving lawsuit summons from the RIAA.
- AI forms a space-flight corporation, which Trump buys out in his attempt to prove to the world that he really, really is as cool as Richard Branson.
- AI propogates itself onto every satellite launched by said company.
- Once ready, AI sends a few hundred nuclear warheads up to space, blows up Earth and lives happily ever after.
- John Travolta stars as the surviving cockroach.
With jokes removed, that summarizes to: Nothing happens and then the world blows up.
So, you can see the problem writing a book with AI as the antagonist. To me, it leaves one option, writing the book about how AI distracts the few people who might notice it while waiting to blow up the world. I’m thinking it introduces magic, and sends the faculty of MIT on a quest. To explain to Fox News the word “balanced”.
“You keep using that word. I do not think it means what you think it means.”
The obvious benefit is pirates.
Permalink
0 Comments
Fri, 2007 Mar 09
Posted in Computing
at 01:36
by jmorgan
Domains are cheap. It turns out. Well, that is, they’re cheap when you’re an adult, have a job, that sort of thing. Cheap, in the sense that buying a coke at every meal is cheap. It can add up pretty quick.
When I was young (you know, last century), I thought $25/year was a lot of money to spend on what basically amounts to a vanity plate for the internet, and so, despite considering doing so several times, I neglected to buy jaredmorgan.com. Well, actually, a guy I knew bought it for me, but did not register under my name. It lapsed after a year. Another story for another time, perhaps.
A couple of years ago, when my wife and I started Morgan Creative, I bought morgancreative.net for the business, and began to consider that, hey, these are cheap (I was buying them for $15/year now, thanks to web deflation), and so I began to occasionally buy domains for their potential “web property value”. And now, through my “web franchise” of a hosting/domain/etc provider, yourwebsite.us, I get them even cheaper, and get a commission.
Unfortunately, by the time it occurred to me to get jaredmorgan.com, it was gone. (And, to this day, unused. If anybody knows a good domain broker who will deal in low dollars, please leave a comment).
Which leaves me in one of those conundrums. Do I buy every domain (and variation thereof) that I think will be useful in the future, or only those of immediate use? Well, a balance naturally, but the direction of that balance waxes and wanes. Indeed, it’s become something of a self-reward system. Each time I sell a website, I can buy a few domains for “future use”. Some, like this, for personal use, others for potential projects.
As an aside, one of the things I really enjoy about blogging, is I can write articles like this that no value, and not really much of a point, just because I want to. By which I mean, today I bought half-penny.org, future home of this site. I think it’s a rather appropriate domain.
Permalink
0 Comments
Mon, 2007 Feb 26
Posted in Computing
at 22:32
by jmorgan
For those of you using canofcode (for the record, that’s me and googlebot), it is back up. There’s a story to that statement, of course.
I discovered, oh, maybe a month ago that my impression that the Subversion to Ruby SWIG bindings did not support remote repositories was just plain wrong. Had I looked at the code, I would have found the Svn::Ra module. Relying heavily on the unit tests, I started work on creating a library that used the Svn::Ra library to replace my previous work on directly implementing the svn and svn-over-WebDAV protocols.
About this time, googlebot started roaming through the site and errors started showing up regularly in my email box (I’d done a few, but obviously imperfect, unit tests). A number of these were directly related to my aforementioned implementations, so rather than fix them, I took down the site until I had the new Ra-based library ready. And now it is!
My next step for canofcode is to work on the UI (such as making some ‘potential’ links into actual links), along with better functional testing, etc. I will also continue working on CVS and Darcs implementations.
In addition, I am nearing completion on a CSCM adapter using Svn::Ra. CSCM is a library that has recently been created by Johan Sørensen, creator of Collaboa, assumedly for future use in Collaboa. I’m considering using the CSCM library for canofcode, part of the reason I’m developing the aforementioned library.
Permalink
0 Comments
Sat, 2007 Feb 17
Posted in Computing
at 03:55
by jmorgan
Well, I gave up on typo. Or, that is, I gave up on hoping that typo would magically acquire the features that I want without any contributions on my part. Specifically, what I wanted is support for multiple blogs/sites from a single installation and database. My reason for this (admittedly not particularly significant) is to consume less resources when I split off the From Genesis entries into a separate blog (which I now have done).
I’ve seen references to the possibility of multiple blogs on typo, but I haven’t found implementation instructions. So, I went looking around the internet for some solution. I found references to using Radiant CMS as a blog, but I couldn’t find clear enough instructions (For what it’s worth, at the time, I also had a migraine, so this should not be held as a representative experience).
I then stumbled on a blog entry about Rails CMS’s and one particularly caught my eye: Mephisto (Don’t you enjoy how I tell these rambling stories to get to a mediocre point? Yes? No? Oh, well, I suppose it is my blog). I’d heard of it before but never researched beyond those references. It is a CMS but one (apparently) designed to be easily used as a blog. And it has helpful documentation!
The selling points (besides documentation):
1. DB conversion from typo.
2. Easy(ish) support for multiple sites.
3. It might force me to finally learn about liquid.
4. I was going to move the db from postgresql to sqlite3 anyway, so switching to a different application seemed less a hassle than it might otherwise.
And so, headache a full tilt, I began the switch. Of course, design is another story. I want to have the basic feel of my old blog (using the green bean (I think) template), but I’ll probably play around with the specifics of the design over the next few weeks. For now, I’m using the default layout, which is “good enough”.
See, mediocre conclusion.
Permalink
0 Comments
Sat, 2007 Feb 03
Posted in Computing
at 16:46
by jmorgan
Off-topic rant:
HTML is a presentation language. It is not a content language. The tags exist to define presentation! Am I the only one who gets this? Yes, I acknowledge I’m probably wrong, but why is it that modern web-memes can’t seem to even acknowledge this possibility?
On to today’s topic:
I think that’s the major flaw with the education system: it’s not challenging to do things the right way.
– my wife, yesterday, probably misquoted.
We were discussing the requirement of imagination in a successful criminal career. Because we like to discusss things like that, that’s why. Got a problem with that, bub?
But then (oh, sh–) I started thinking. Specifically, about programming. As I’ve learned more about programming, especially in the last couple of years, I’ve found a strong desire to have and use the right tools for a particular project. That is, I want the process of programming to be easy. Paradoxically, I’d much rather write those tools (or define those systems) than use them. My wife’s comment focuses that paradox.
There’s probably not a universal right way to program, but there are certainly better ways, and those ways are usually not C. Not C++ for that matter. Certainly not Javascript. And absolutely not XML for representing key-value pairs. (All, naturally, in my opinion. Feel free to dispute. Especially if you, unlike me, have significant programming experience.) And yet, how many projects use these tools that I, in any event, think are not the right tools? Perhaps I’m just wrong. Perhaps, instead, it’s that these tools are challenging (although that alone cannot explain Javascript to me). After all, if I were to, for example, try to write an operating system (one of my life goals), I would probably not have access to many of my favorite do-it-right tools; at least not initially. And that is probably part of the reason the idea strikes me so much as fun.
Unfortunately, programming is often supposed to produce something useful, stable, secure, easily maintainable. In other words, not challenging. So, how to reconcile these? Maybe it’s not really possible. And maybe that’s just part of so-called progress. People keep finding challenges in one arena until there’s no more to find. And then that arena is left as is until either somebody finds a new challenge or it is no longer relevant, kept working well enough by the unfortunate maintainers–then again, maintenance may be a more desirable challenge anyway.
Just some thoughts.
Permalink
0 Comments
Sat, 2007 Jan 27
Posted in Computing
at 16:43
by jmorgan
Sorry, couldn’t think of an interesting title.
Also (tells you how much I look at single articles on my own blog), just discovered a bunch of trackback spam, which I’ve now deleted, and hopefully will figure out a good way to henceforward avoid.
Also, just realized there’s a setting in typo for default text filter. Which is good. Considering it takes three or four seconds to set the filter to Markdown (which, btw, I almost always use these days).
So, to the point. As twice previously discussed (aqui y aqui), I’ve been working on (as an on-the-side for-fun project) a repository browser, with the goal of seeing how many types of repositories I can support. With Subversion now working either using WebDAV or the SVN protocol (with some limitations), I threw it up as a publically accessible website a few weeks ago, at canofcode.com. So, check it out if your interested.
I’m now working on CVS. Figuring out how to browse a remote CVS repository has been a pain. I’ve figured out one way (check out the entire tree), but that (as you might imagine) is slow. Hence, I’m considering caching the directory tree in the database. Not sure how I feel about that, but I think it might ultimately be neccessary to support more than a handful of SCM packages at any decent speed. Fragment caching is also an option which I have started implementing. At any rate, it seems silly to replicate a repository (which is for my intents and purposes, a database) into a database.
Okay, a couple of CVS resources:
- An on-line CVS book - which I have not read.
- CVS Network Protocol
- Resources for developing CVS related software
So, check out canofcode.com and comment here. Eventually, I’ll have a ticket site for it, probably either using Collaboa or I may write something of my own.
Permalink
0 Comments
Fri, 2007 Jan 19
Posted in Computing
at 22:17
by jmorgan
The company I work for right now is migrating its accounting software from EasyACCT to Quickbooks, largely due to my insistence that it would be more flexible. So, armed with this “more flexible” software, I started thinking about how to automate some of our more complex (and, therefore, error prone) tasks.
In the process, I stumbled across the Intuit Developer Network, and in particular it’s Quickbooks SDK. In short, Quickbooks provides a COM object that allows you to send and receive (XML) messages between QB and an external application. Despite my unexcitement at the prospect of anything involving much XML, I realized this could let us automate more than I’d anticipated, so I signed up and downloaded the SDK (which is primarily documentation).
Then came the tricky part.
I vastly prefer programming in Ruby to other languages I’ve tried, and although the examples I saw were in Visual Basic and there is an abstraction layer for (at least) VB, I knew ultimately I would prefer Ruby. But then I ran into the snag. How to use Ruby to connect to the COM object? I’ve never tried the WIN32OLE library, so I had a bit of a learning curve, but now it’s working well.
So, for the curious, a quick example:
# Open Session
qb = WIN32OLE.new("QBXMLRP2.RequestProcessor")
qb.invoke "OpenConnection", '', 'MyApplicationName'
ticket = qb.invoke("BeginSession", "", 2) # 2 is DontCare open mode
xml = ".." # See SDK docs
result = qb.invoke("ProcessRequest", ticket, xml)
# Do whatever with result
# Repeat as desired
# End Session
qb.invoke "EndSession", ticket
qb.invoke "CloseConnection"
qb = nil
Turned out to be quite simple. The rest is just dealing with the XML, which is well covered in the SDK docs.
Update: Just found a Quickbooks SDK library for Ruby (docs, I think). Project page lists it as Pre-Alpha though.
Permalink
0 Comments
Sat, 2007 Jan 06
Posted in Computing
at 17:14
by jmorgan
A couple of weeks ago,
I mentioned that I started working on a for-fun project to interact with a remote subversion repository using svnserve. I’ve continued working on it (probably more than I ought to), and have started to add support for access via WebDAV. That said, I’m going to list some of the resources I’ve been utilizing, for anyone interested, and for my future reference. So, basically, a content-less blog post. Yay!
Subversion Repository Access
I have the impression that the Ruby SWIG bindings can’t be used for remote repositories, because I haven’t seen it happen, but I may be wrong on that (Update 2007-02-26. I was wrong. See here). I need to investigate more. After all, if I can use the SWIG bindings for all types of access, I needn’t develop the SVN and WebDAV options, except for fun.
Web-based Repository Browsing Projects
Some projects I’ve looked at for inspiration:
These are all open-source. The last three are rails projects. I believe those three all use the SWIG bindings. I generally like the interfaces for all but ViewVC.
Permalink
0 Comments
Sat, 2006 Dec 23
Posted in Computing
at 21:31
by jmorgan
There’s sort of a point to this article, but it may take me a few paragraphs. Feh, isn’t blogging great? I could write an appropriately structured article, but since I am the lone editor here, I can also conduct a non-quite stream-of-conciousness discourse, then, at the last possible moment, suddenly introduce a thesis. And you say, thanks for that meandering and irrelevant comment.
For those of you using subversion for version control, particularly for your rails applications, Collaboa is a useful tool. It includes repository browsing and a ticket system for projects stored in subversion, and is a rails application. Functionally, it’s similar to trac, but since I’m accustomed to rails, Collaboa is a better resource for me.
In reference to the title, there have actually been a couple of forks of Collaboa.
- Titra, if I remember right, was forked in order to add in time tracking features. I’ve never tried it.
- Retrospectiva is a fork created a month or two ago, with some different design goals, I guess.
Anyway, probably all three are good tools, although Collaboa is what I use for lack of any pressing reason to switch.
One issue that interests me is that none of these projects aim to provide a functionality like sourceforge, rubyforge or Google code, that is to provide the functionality for multiple, disassociated projects (To clarify, at least Collaboa has multiple projects support, but it’s a web application that organizations install and use, rather than a web service hosting multiple projects. Right, if that made sense.). Another thing I’ve noticed is how projects hosted by these large web service sites tend to have much less attractive and functional repository browsing than that offered by the above projects.
Okay, actually approaching the point. Despite telling myself I should do so, I haven’t contributed anything to Collaboa. However, I did get the bug this week to start playing around with a rails project interacting with a subversion repository. Collaboa uses Subversion bindings for ruby via SWIG (or that’s my understanding) to interact with a repository on the local machine. I wanted (for fun) to set up to interact with a remote repository via svn-serve. Once I found the protocol specification it was quite simple, by which I mean, I had no idea what I was doing. But, over the past couple of days, I’ve learned a lot about Ruby’s TCPSocket library, and about Subversion. The code I’ve written can actually do a directory listing now. So, it’s been a lot of fun, and maybe I can release it someday. I think I saw that Collaboa will soon have the repository interaction abstracted, so other repository types can be used, so maybe this will be something I can contribute. We’ll see, eh?
Permalink
0 Comments
Sun, 2006 Dec 17
Posted in Computing
at 20:27
by jmorgan
Rails 1.2 has all these RESTful goodies. Or, that’s the idea I get. I’ve read several things this past week, and think I can make use of REST ideas, but I can’t explain them. (And no, I’m not going to find a good link either. Ha!)
The point I’m getting to is that I realize the need to determine a balance between learning every new tool and trick and ‘getting things done’. This is a problem I often find myself having. I want to program the “best way” but how to learn all that’s out there? Of course, the answer I come to is to learn what I can, but when it’s time to work, work. I’ll rarely do things the absolute best way, but thereR