|
Friday, 02 April 2010 11:41 |
The following demonstrates how to install and run Rack-GTK2 on Debian Squeeze. Rack-GTK2 makes it possible to sends code statements into the Ruby GTK application through the Rack Web server interface which accepts HTTP requests on localhost.
*installation*
apt-get install the following:
libgtk2-ruby
rubygems
librack-ruby
mongrel
Then execute rack-gtk2
ruby1.8 gtk_rack2.rb
file: gtk_rack2.rb
#! /usr/bin/env ruby
#file: gtk_rack.rb
require 'rubygems'
require 'rack'
require 'rackrscript'
require 'gtk2'
class RubyApp < Gtk::Window
def initialize
super
init_ui()
init_webserver()
end
def init_ui()
set_default_size(400,400)
show_all.signal_connect("destroy"){Gtk.main_quit}
end
def init_webserver()
Thread.new{
rack_rscript = Proc.new do |env|
req = Rack::Request.new(env)
package_id, *jobs = req.params['package'], req.params['job']
*args = req.params['arg']
url_base = "http://rorbuilder.info/r/heroku-rack/"
rsf_url = "%s%s.rsf" % [url_base, package_id]
@content_type = "text/html"
args = [jobs.map {|x| "//job:" + x}.join("\n"), rsf_url]
rs = RScript.new()
code = rs.run(args)
content = eval(code.join)
[200, {"Content-Type" => @content_type}, content]
end
Rack::Handler::Mongrel.run rack_rscript, :Port => 9292
}
end
end
Gtk.init
window = RubyApp.new
Gtk.main
Tested Observed
------- ---------
[executed gtk_rack2.rb] the gtk application was visible
http://localhost:9292/?package=r&job=gtk-run nothing to observe (although gtk controls were loaded into the application)
http://localhost:9292/?package=r&job=show-text see screenshot of 'a b c d 1 2 3 4' within the GTK application window [twitxr.com]
Resources:
- Embed Rack-Rscript in your Ruby-GTK application [dzone.com]
 Read more: |
|
Saturday, 27 March 2010 16:33 |
The Dynarex gem makes it convenient to read Dynarex records as a hash.
*Installation*
sudo gem1.9.1 install dynarex
Successfully installed dynarex-0.1.0
1 gem installed
Installing ri documentation for dynarex-0.1.0...
Updating class cache with 2747 classes...
Installing RDoc documentation for dynarex-0.1.0...
*example*
require 'dynarex'
url = 'https://dl.dropbox.com/u/709640/scotruby2010-all.xml'
users = Dynarex.new(url).records
# display the top 5 twitter users with the most followers
users.sort_by {|x| -x[:followers_count].to_i}[0..4].each_with_index do |user, i|
puts "%d %+4s %s" % [i+1, user[:followers_count], user[:twitter_name]]
end
output:
1 8947 timbray
2 2510 jimweirich
3 2228 marick
4 1837 chacon
5 1619 objo
Here's the code for the Dynarex class
class Dynarex
include REXML
def initialize(location)
open(location)
end
def summary
@summary
end
def records
@records
end
private
def open(location)
if location[/^https?:\/\//] then
buffer = Kernel.open(location, 'UserAgent' => 'Dynarex-Reader').read
else
buffer = File.open(location,'r').read
end
@doc = Document.new buffer
@summary = summary_to_h
@records = records_to_h
end
def display()
puts @doc.to_s
end
def records_to_h
XPath.match(@doc.root, 'records/*').map do |row|
XPath.match(row, '*').inject({}) do |r,node|
r[node.name.to_s.to_sym] = node.text.to_s
r
end
end
end
def summary_to_h
XPath.match(@doc.root, 'summary/*').inject({}) do |r,node|
r[node.name.to_s.to_sym] = node.text.to_s
r
end
end
end
Resources:
Dynarex [github.com]
 Read more: |
|
|
Tuesday, 23 March 2010 11:12 |
The following example parses a string containing a quoted string:
s = %q(passed "abc def" etert)
s.gsub!(/\".[^\|\'"]+["']/) {|x| x.gsub(/\s/,'%20')}
a = s.split(/\s/).map {|x| x.gsub(/%20/,' ')}
#=> ["passed", "\"abc def\"", "etert"]
*update: 23-Mar-2010 @ 1:50pm*
Here's how to remove the quotes from the final result:
a = s.split(/\s/).map {|x| x.gsub(/%20/,' ').sub(/\"(.*)\"/,'\1')}
#=> ["passed", "abc def", "etert"]
 Read more: |
|
Wednesday, 03 March 2010 12:24 |
// description of your code here
############################################################################
# Python-Qt template script for amaroK
# (c) 2005 Mark Kretschmann <
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
>
#
# Depends on: Python 2.2, PyQt
############################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
############################################################################
import ConfigParser
import os
import Queue
import sys
import threading
import urllib
import commands
import shutil
import subprocess
import mutagen
from mutagen.id3 import APIC
try:
from qt import *
except:
os.system( "kdialog --sorry 'CopyCover error: PyQt (Qt bindings for Python) is required for this script.'" )
raise
debug_prefix = "[AmaroK CopyCover Script]"
class ConfigDialog( QDialog ):
""" Configuration widget """
def __init__( self ):
self.load()
QDialog.__init__( self )
self.setWFlags( Qt.WDestructiveClose )
self.setCaption( "Copy cover script - amaroK" )
self.lay = QHBoxLayout( self )
self.vbox = QVBox( self )
self.lay.addWidget( self.vbox )
self.hbox1 = QHBox( self.vbox )
self.hbox1.setMargin(5)
QLabel( "What filename should I use for album covers ?", self.hbox1 )
self.hbox2 = QHBox( self.vbox )
self.hbox2.setMargin(5)
self.albumName = QCheckBox( QString("Use album name"), self.hbox2 )
self.hbox3 = QHBox( self.vbox )
self.hbox3.setMargin(5)
QLabel( "Always use this filename : ", self.hbox3 )
self.filenameEdit = QLineEdit( self.hbox3 )
self.connect( self.albumName, SIGNAL("toggled(bool)"), self.filenameEdit, SLOT('setDisabled(bool)') )
self.connect( self.albumName, SIGNAL("toggled(bool)"), self.filenameEdit, SLOT('setDisabled(bool)') )
if self.filename == "albumname":
self.filenameEdit.setText("cover.png")
self.albumName.setChecked(True)
else:
self.albumName.setChecked(False)
self.filenameEdit.setText(self.filename)
self.filenameEdit.setFocus()
# Change folder icon
self.hbox4 = QHBox( self.vbox )
self.hbox4.setMargin(5)
self.desktopEntry = QCheckBox( QString("Change folder icon"), self.hbox4 )
if self.createDE:
self.desktopEntry.setChecked(True)
else:
self.desktopEntry.setChecked(False)
# Remove cover from cache
self.hbox5 = QHBox( self.vbox )
self.hbox5.setMargin(5)
self.removeCoverBox = QCheckBox( QString("Remove from amaroK's cache after copy"), self.hbox5 )
if self.removeCover:
self.removeCoverBox.setChecked(True)
else:
self.removeCoverBox.setChecked(False)
self.hboxOk = QHBox( self.vbox )
self.hboxOk.setMargin(5)
self.ok = QPushButton( self.hboxOk )
self.ok.setText( "Ok" )
self.cancel = QPushButton( self.hboxOk )
self.cancel.setText( "Cancel" )
self.cancel.setDefault( True )
self.connect( self.ok, SIGNAL( "clicked()" ), self.save )
self.connect( self.cancel, SIGNAL( "clicked()" ), self, SLOT( "reject()" ) )
self.adjustSize()
def load( self ):
""" Loads configuration from file """
self.config = ConfigParser.ConfigParser()
try:
self.config.read( "copycoverrc" )
except:
debug( "No config file found, using defaults." )
self.filename = "cover.png"
self.createDE = False
self.removeCover = False
if self.config.has_option("General", "filename"):
self.filename = self.config.get("General", "filename")
else:
self.filename = "cover.png"
# desktop entry
if self.config.has_option("General", "createDesktopEntry"):
self.createDE = self.config.getboolean("General", "createDesktopEntry")
else:
self.createDE = False
# remove cover
if self.config.has_option("General", "removeCover"):
self.removeCover = self.config.getboolean("General", "removeCover")
else:
self.removeCover = False
def save( self ):
""" Saves configuration to file """
self.file = open( "copycoverrc", 'w' )
self.config = ConfigParser.ConfigParser()
self.config.add_section( "General" )
if self.albumName.isChecked():
self.config.set( "General", "filename", "albumname" )
else:
filename = str( self.filenameEdit.text() )
self.config.set( "General", "filename", filename )
if self.desktopEntry.isChecked():
self.config.set( "General", "createDesktopEntry", "yes" )
else:
self.config.set( "General", "createDesktopEntry", "no" )
if self.removeCoverBox.isChecked():
self.config.set( "General", "removeCover", "yes" )
else:
self.config.set( "General", "removeCover", "no" )
self.config.write( self.file )
self.file.close()
self.accept()
class CopyCover( QApplication ):
""" The main application, also sets up the Qt event loop """
def __init__( self, args ):
QApplication.__init__( self, args )
debug( "Started." )
self.queue = Queue.Queue()
self.startTimer( 100 )
# Start separate thread for reading data from stdin
self.stdinReader = threading.Thread( target = self.readStdin )
self.stdinReader.start()
self.readSettings()
def saveState(self):
# script is started by amarok, not by KDE's session manager
sessionmanager.setRestartHint(QSessionManager.RestartNever)
def readSettings( self ):
""" Reads settings from configuration file """
self.filename = "cover.png"
self.createDE = False
self.removeCover = False
config = ConfigParser.ConfigParser()
try:
config.read( "copycoverrc" )
except:
debug( "No config file found, using defaults." )
if config.has_option("General", "filename"):
self.filename = config.get("General", "filename")
if config.has_option("General", "createDesktopEntry"):
self.createDE = config.getboolean("General", "createDesktopEntry")
if config.has_option("General", "removeCover"):
self.removeCover = config.getboolean("General", "removeCover")
############################################################################
# Stdin-Reader Thread
############################################################################
def readStdin( self ):
""" Reads incoming notifications from stdin """
while True:
# Read data from stdin. Will block until data arrives.
line = sys.stdin.readline()
if line:
self.queue.put_nowait( line )
else:
break
############################################################################
# Notification Handling
############################################################################
def timerEvent( self, event ):
""" Polls the notification queue at regular interval """
if not self.queue.empty():
string = QString( self.queue.get_nowait() )
debug( "Received notification: " + str( string ) )
if string.contains( "configure" ):
self.configure()
if string.contains( "engineStateChange: play" ):
self.engineStatePlay()
if string.contains( "engineStateChange: idle" ):
self.engineStateIdle()
if string.contains( "engineStateChange: pause" ):
self.engineStatePause()
if string.contains( "engineStateChange: empty" ):
self.engineStatePause()
if string.contains( "trackChange" ):
self.trackChange()
# Notification callbacks. Implement these functions to react to specific notification
# events from amaroK:
def configure( self ):
debug( "configuration" )
self.dia = ConfigDialog()
self.dia.show()
self.connect( self.dia, SIGNAL( "destroyed()" ), self.readSettings )
def engineStatePlay( self ):
""" Called when Engine state changes to Play """
pass
def engineStateIdle( self ):
""" Called when Engine state changes to Idle """
pass
def engineStatePause( self ):
""" Called when Engine state changes to Pause """
pass
def engineStateEmpty( self ):
""" Called when Engine state changes to Empty """
pass
def trackChange( self ):
""" Called when a new track starts """
try:
self.copyCover()
except Exception, e:
message = "The CopyCover amaroK script has run into an unhandled error. " \
+"I'm sorry about it, but please tell me about this error, " \
+"and help improve the script !\nThe error message was:\n" \
+"%s\nPlease look at the end of your ~/.xsession-errors " % e \
+"file for error messages too. Thanks."
os.system("kdialog --title \"AmaroK CopyCover Script\" --sorry \"%s\"" % message)
def copyCover(self):
""" Copy a cover to a song's directory """
cover = commands.getoutput("dcop amarok player coverImage")
str_cacheFileName = os.path.basename(cover)
str_cacheDir = os.path.dirname(cover)
str_baseDir = os.path.dirname(str_cacheDir)
str_largeDir = os.path.join(str_baseDir, "large")
str_largeFileName = str_cacheFileName.split("@")[1]
if os.path.exists(os.path.join(str_largeDir, str_largeFileName)):
cover = os.path.join(str_largeDir, str_largeFileName)
if cover.endswith('nocover.png'):
return
songDir = self.getAlbumDir()
if not os.path.exists(songDir):
debug("ERROR: Invalid dirname: %s" % songDir, level=2)
return
filename = self.getCoverName()
target = os.path.join(songDir, filename)
target_jpg = os.path.join(songDir, "cover.jpg")
alreadyThere = False
"""for file in os.listdir(songDir):
if file.lower()[-4:] in ['.png', '.jpg', '.gif']:
alreadyThere = True"""
if not alreadyThere:
if os.path.exists(cover):
debug("copy %s to %s" % (cover, target))
if not os.access(songDir, os.W_OK):
debug("ERROR: No write access to %s" % songDir, level=2)
return
shutil.copyfile(cover, target)
"""os.system("kdialog --title \"AmaroK CopyCover Script\" --sorry \"%s\"" % target)"""
cmd=["convert", target, target_jpg]
subprocess.call(cmd)
imagedata = open(target_jpg, 'rb').read()
mp3file = commands.getoutput("dcop amarok player path")
audio = mutagen.File(mp3file)
audio.tags.add(APIC(3, 'image/jpg', 3, 'Front cover', imagedata))
audio.tags.save()
audio.save
if self.removeCover:
os.remove(cover)
if self.createDE:
self.createDesktopEntry()
def getAlbumDir(self):
""" Finds the album directory """
songURL = commands.getoutput("dcop amarok player encodedURL")
song = urllib.unquote(songURL)
# A song URL usually looks like file:///path/to/song,
# but sometimes it can be file:/path/to/song
song = song.replace("file://", "").replace("file:", "")
return os.path.dirname(song)
def getCoverName(self):
""" Finds the cover name (could be from the album name) """
if self.filename != "albumname":
return self.filename
albumName = commands.getoutput("dcop amarok player album")
if not albumName:
return "cover.png"
illegal_chars = [' ', '/', '"', '*', ':', '<', '>', '?', '\\', '|' ]
for char in illegal_chars:
if albumName.count(char) > 0:
albumName = albumName.replace(char, "")
return albumName + ".png"
def createDesktopEntry(self):
""" Creates the desktop entry to change the folder's icon to the album cover """
songDir = self.getAlbumDir()
alreadyThere = False
for file in os.listdir(songDir):
if file == ".directory":
alreadyThere = True
if not alreadyThere:
desktopEntry = open(os.path.join(songDir, ".directory"), "w")
desktopEntry.write("[Desktop Entry]\nIcon=./%s\n" % self.getCoverName())
desktopEntry.close()
debug("desktop file created in %s" % songDir)
############################################################################
def debug( message, level=2 ):
""" Prints debug message to stdout """
if level == 1: # appears only if lauched from the command line (amarokapp)
sys.stdout.write(debug_prefix + " " + message + "\n")
if level >= 2: # appears in ~/.xsession-errors
sys.stderr.write(debug_prefix + " " + message + "\n")
if level >= 3:
os.system("kdialog --title \"%s\" --sorry \"%s\"" % (debug_prefix, message))
def main( args ):
app = CopyCover( args )
app.exec_loop()
if __name__ == "__main__":
main( sys.argv )
 Read more: |
|