From m.fellinger at gmail.com Mon Nov 19 11:26:55 2007 From: m.fellinger at gmail.com (Michael Fellinger) Date: Tue, 20 Nov 2007 01:26:55 +0900 Subject: [Rg 112] [ANN] Ramaze version 0.2.0 Message-ID: <9c00d3e00711190826j69898a75o5cdcba9d92646713@mail.gmail.com> This time we are proud to announce Version 0.2.0 of the Ramaze framework, a light and modular open source web framework. This release features a lot of work directly from our community and i am really greatful for everybody who helped in testing, patching and contributing new exciting features. An extensive set of specs and docs is covering almost every detail of the implementation and usage. It is under development by a growing community and in production-use at companies. Special (alphabetic) thanks go to: Aman 'tmm1' Gupta - tons of patches, specs and support Jonathan 'Kashia' Buch - patches for localization Riku R?is?nen - as usual, extensive testing Pistos - submitted his first patch Stephan Maka - XSLT templating, implementation, specs and examples Home page: http://ramaze.rubyforge.org IRC: #ramaze on irc.freenode.net Short summary of changes from 0.1.4 to 0.2.0: - Contrib facility, for simple experimental user-contributions - Routes - As always, lots of bugfixes - complete XSLT templating system, usage and specs - Improved localization filter - Added gzip filter - Support for the new upcoming nagoro templating engine. - Tool::Tidy is gone for good A complete Changelog is available at http://manveru.net/ramaze/doc/CHANGELOG Known issues: - none yet, waiting for your reports :) Features: - Builds on top of the Rack library, which provides easy use of adapters like Mongrel, WEBrick, CGI or FCGI. - Supports a wide range of templating-engines like: Amrita2, Erubis, Haml, Liquid, Markaby, Remarkably and its own engine called Ezamar. - Highly modular structure, you can just use the parts you like. This also means that it's very simple to add your own customizations. - A variety of helpers is already available, giving you things like advanced caching, OpenID-authentication or aspect-oriented programming for your controllers. - It is possible to use the ORM you like, be it ActiveRecord, Og, Kansas or something more simplistic like a wrapper around YAML::Store. - Good documentation: although we don't have 100% (dcov says around 75%) documentation right now, just about every part of Ramaze is covered with basic and advanced docs. There are a variety of examples and a tutorial available. - Friendly community: lastly, but still quite important, there are people from all over the world using Ramaze, so you can get almost instant help and info. For more information please come to http://ramaze.rubyforge.org or ask directly on IRC (irc://irc.freenode.net/#ramaze) Thank you, Michael 'manveru' Fellinger and the Ramaze community From john at oxyliquit.de Fri Nov 30 13:41:41 2007 From: john at oxyliquit.de (Jonathan Buch) Date: Fri, 30 Nov 2007 19:41:41 +0100 Subject: [Rg 113] [PATCH] gettext contrib module Message-ID: <20071130184141.GA17647@oxyliquit.de> Hi, module for localization via gettext. Please don't push to darcs head without at least one other guy trying it. :) Jo -------------- next part -------------- New patches: [Add gettext contrib, localize ramaze via gettext Jonathan Buch **20071130183535] { adddir ./lib/ramaze/contrib/gettext addfile ./lib/ramaze/contrib/gettext.rb hunk ./lib/ramaze/contrib/gettext.rb 1 +# Copyright (c) 2006 Michael Fellinger m.fellinger at gmail.com +# All files in this distribution are subject to the terms of the Ruby license. + +require 'ramaze/tool/localize' +require 'ramaze/contrib/gettext/mo' +require 'ramaze/contrib/gettext/po' + +# Gettext helps transforming arbitrary text into localized forms using +# a simple regular expression and substituting occurences with translations +# stored in .mo files. +# +# == MO generation +# +# See http://www.gnu.org/software/gettext/ for a general overview over +# Gettext. Generally it's easier to use a graphical translator like Poedit. +# +# The default language is en, a .po template file will be saved by default +# under `conf/locale_en.mo.pot`. Individual languages are by default looked +# up at `conf/locale_fi.mo` for localization. +# +# == Usage: +# +# Ramaze::Dispatcher::Action::FILTER << Ramaze::Tool::Gettext + +class Ramaze::Tool::Gettext < Ramaze::Tool::Localize + + # Enable Localization + trait :enable => true + + # Default language that is used if the browser don't suggests otherwise or + # the language requested is not available. + trait :default_language => 'en' + + # languages supported + trait :languages => %w[ en ] + + # YAML files the localizations are saved to and loaded from, %s is + # substituted by the values from trait[:languages] + trait :file => 'conf/locale_%s.mo'.freeze + + # The pattern that is substituted with the translation of the current locale. + trait :regex => /\[\[(.*?)\]\]/ + + # Browsers may send different keys for the same language, this allows you to + # do some coercion between what you use as keys and what the browser sends. + trait :mapping => { 'en-us' => 'en', 'ja' => 'jp'} + + # When this is set to false, it will not save newly collected translatable + # strings to disk. Disable this for production use, as it slows the + # application down. + trait :collect => true + + + # Load given locales from disk and save it into the dictionary. + + def self.load(*locales) + Ramaze::Inform.debug "loading locales: #{locales.inspect}" + + dict = trait[:dictionary] || {} + + locales.each do |locale| + begin + dict[locale] = ::MOFile.open(trait[:file] % locale) + rescue Errno::ENOENT + Ramaze::Inform.error "couldn't load #{trait[:file] % locale}" + dict[locale] = {} + end + end + + trait[:dictionary] = dict + end + + # Reloads given locales from the disk to refresh the dictionary. + + def self.update + trait[:dictionary] = nil + dictionary.each do |locale, dict| + if dict.kind_of?(MOFile) + Ramaze::Inform.debug("Reloading #{dict.filename}") + dict.update! + end + end + end + + # Stores given locales from the dictionary to disk. + + def self.store(*locales) + keys = [] + dictionary.each do |locale, dict| + keys.concat dict.keys + end + + data = ::GetText::RGetText.generate(keys.compact.uniq.sort.map {|x| [x] }) + file = (trait[:file] % trait[:default_language]) + '.pot' + File.open(file, File::CREAT|File::TRUNC|File::WRONLY) do |fd| + fd.write data + end + rescue Errno::ENOENT => e + Ramaze::Inform.error e + end + +end + +class Ramaze::Contrib::Gettext + + # Called by Ramaze::Contrib.load, adds Gettext to Action::Filter + + def self.startup + Ramaze::Dispatcher::Action::FILTER << Ramaze::Tool::Gettext + end +end addfile ./lib/ramaze/contrib/gettext/mo.rb hunk ./lib/ramaze/contrib/gettext/mo.rb 1 +=begin + mo.rb - A simple class for operating GNU MO file. + + Copyright (C) 2003-2006 Masao Mutoh + Copyright (C) 2002 Masahiro Sakai, Masao Mutoh + Copyright (C) 2001 Masahiro Sakai + + Masahiro Sakai + Masao Mutoh + + You can redistribute this file and/or modify it under the same term + of Ruby. License of Ruby is included with Ruby distribution in + the file "README". + + $Id: mo.rb,v 1.7 2006/06/11 15:36:20 mutoh Exp $ +=end + +require 'iconv' + +class MOFile < Hash + class InvalidFormat < RuntimeError; end; + + attr_reader :filename + + Header = Struct.new(:magic, + :revision, + :nstrings, + :orig_table_offset, + :translated_table_offset, + :hash_table_size, + :hash_table_offset) + + MAGIC_BIG_ENDIAN = "\x95\x04\x12\xde" + MAGIC_LITTLE_ENDIAN = "\xde\x12\x04\x95" + + def self.open(arg = nil, output_charset = nil) + result = self.new(output_charset) + result.load(arg) + end + + def initialize(output_charset = nil) + @filename = nil + @last_modified = nil + @little_endian = true + @output_charset = output_charset + super + end + + def update! + if FileTest.exist?(@filename) + st = File.stat(@filename) + load(@filename) unless (@last_modified == [st.ctime, st.mtime]) + else + puts "#{@filename} was lost." if $DEBUG + clear + end + self + end + + def load(arg) + case arg + when String + begin + st = File.stat(arg) + @last_modified = [st.ctime, st.mtime] + rescue Exception + end + load_from_file(arg) + when IO + load_from_stream(arg) + end + @filename = arg + self + end + + def load_from_stream(io) + magic = io.read(4) + case magic + when MAGIC_BIG_ENDIAN + @little_endian = false + when MAGIC_LITTLE_ENDIAN + @little_endian = true + else + raise InvalidFormat.new("Unknown signature %s" % magic.dump) + end + + header = Header.new(magic, *(io.read(4 * 6).unpack(@little_endian ? 'V6' : 'N6'))) + raise InvalidFormat.new(sprintf("file format revision %d isn't supported", header.revision)) if header.revision > 0 + + io.pos = header.orig_table_offset + orig_table_data = io.read((4 * 2) * header.nstrings).unpack(@little_endian ? 'V*' : 'N*') + + io.pos = header.translated_table_offset + trans_table_data = io.read((4 * 2) * header.nstrings).unpack(@little_endian ? 'V*' : 'N*') + + original_strings = Array.new(header.nstrings) + for i in 0...header.nstrings + io.pos = orig_table_data[i * 2 + 1] + original_strings[i] = io.read(orig_table_data[i * 2 + 0]) + end + + clear + for i in 0...header.nstrings + io.pos = trans_table_data[i * 2 + 1] + str = io.read(trans_table_data[i * 2 + 0]) + + if original_strings[i] == "" + if str + @charset = nil + @nplurals = nil + @plural = nil + str.each_line{|line| + if /^Content-Type:/i =~ line and /charset=((?:\w|-)+)/i =~ line + @charset = $1 + elsif /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line + @nplurals = $1 + @plural = $2 + end + break if @charset and @nplurals + } + @nplurals = "1" unless @nplurals + @plural = "0" unless @plural + end + else + if @output_charset + begin + str = Iconv.iconv(@output_charset, @charset, str).join if @charset + rescue Iconv::Failure + if $DEBUG + $stderr.print "@charset = ", @charset, "\n" + $stderr.print "@output_charset = ", @output_charset, "\n" + $stderr.print "msgid = ", original_strings[i], "\n" + $stderr.print "msgstr = ", str, "\n" + end + end + end + end + self[original_strings[i]] = str + end + self + end + + def load_from_file(filename) + @filename = filename + File.open(filename, 'rb'){|f| load_from_stream(f)} + end + + def set_comment(msgid_or_sym, comment) + #Do nothing + end + + + attr_accessor :little_endian, :path, :last_modified + attr_reader :charset, :nplurals, :plural +end addfile ./lib/ramaze/contrib/gettext/po.rb hunk ./lib/ramaze/contrib/gettext/po.rb 1 +#! /usr/bin/env ruby +=begin + rgettext.rb - Generate a .pot file. + + Copyright (C) 2003-2006 Masao Mutoh + Copyright (C) 2001,2002 Yasushi Shoji, Masao Mutoh + + Yasushi Shoji + Masao Mutoh + + You may redistribute it and/or modify it under the same + license terms as Ruby. +=end + + +module GetText + + module RGetText #:nodoc: + extend GetText + + MAX_LINE_LEN = 70 unless defined?(MAX_LINE_LEN) + + module_function + + def generate_pot_header # :nodoc: + time = Time.now.strftime("%Y-%m-%d %H:%M") + off = Time.now.utc_offset + sign = off <= 0 ? '-' : '+' + time += sprintf('%s%02d%02d', sign, *(off.abs / 60).divmod(60)) + + <, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\\n" +"POT-Creation-Date: #{time}\\n" +"PO-Revision-Date: #{time}\\n" +"Last-Translator: FULL NAME \\n" +"Language-Team: LANGUAGE \\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=UTF-8\\n" +"Content-Transfer-Encoding: 8bit\\n" +EOS + end + + def generate_pot(ary) # :nodoc: + str = "" + result = Array.new + ary.each do |key| + msgid = key.shift.dup + curr_pos = MAX_LINE_LEN + key.each do |e| + if curr_pos + e.size > MAX_LINE_LEN + str << "\n#:" + curr_pos = 3 + else + curr_pos += (e.size + 1) + end + str << " " << e + end + msgid.gsub!(/"/, '\"') + msgid.gsub!(/\r/, '') + + str << "\nmsgid \"" << msgid << "\"\n" + str << "msgstr \"\"\n" + end + str + end + + def generate_translated_po(hash) + str = generate_pot_header + result = Array.new + + hash.keys.sort.each do |msgid| + msgid = msgid.dup + msgstr = hash[msgid] + + msgid.gsub!(/"/, '\"') + msgid.gsub!(/\r/, '') + + if msgstr + msgstr.gsub!(/"/, '\"') + msgstr.gsub!(/\r/, '') + end + + str << "\nmsgid \"" << msgid << "\"\n" + str << "msgstr \"" << msgstr << "\"\n" + end + + str + end + + def generate(array) # :nodoc: + str = '' + str << generate_pot_header + str << generate_pot(array) + end + end +end + +if $0 == __FILE__ + require 'yaml' + puts GetText::RGetText.generate_translated_po(YAML.load_file(ARGV[0])) +end } Context: [Add SessionFlash#delete Michael Fellinger **20071130071215] [Failsafe for Request#local_net? - 'unkown' seems to be a common address... Michael Fellinger **20071130070925] [Add lookup for index template like /foo__index Michael Fellinger **20071130035900] [Version 0.2.1 Michael Fellinger **20071128233945] [TAG 0.2.1 Michael Fellinger **20071128233923] [Update CHANGELOG Michael Fellinger **20071128233912] [Use new Request#[] and avoid binding block unnecessarily Aman Gupta **20071128232740] [Spec and fix for bug in String#unindent Michael Fellinger **20071128232359] [Allow multiple keys for Request#[] Michael Fellinger **20071128083242] [Add spec for and fix implementation of Request#local_net? Michael Fellinger **20071128054639] [Allow helper modules to be defined in contrib/ or same file as the app Aman Gupta **20071128035336] [Update to latest Sequel conventions (require 'sequel/sqlite' is deprecated) Aman Gupta **20071127061202] [Doc fixes for contrib/ Aman Gupta **20071127061212] [require 'ramaze/contrib' then Ramaze.contrib :foo is redundant, load 'ramaze/contrib' by default Aman Gupta **20071126231425] [Make StdErr output in specs readable Aman Gupta **20071126231232] [Fix code in comment for gestalt.rb Michael Fellinger **20071126013935] [Fix rcov coverage report generation task Aman Gupta **20071126013705] [support custom caption in openid_login_form rff.rff at gmail.com**20070925133915] [add testcase_require in wikore/spec rff.rff at gmail.com**20070918120027] [coverage task, first try rff.rff at gmail.com**20070904113308] [Fix for nginx caching issue with sourceview's javascript Aman Gupta **20071125161429] [Improve sourceview: add analytics tracking, /path/to/file.rb now works, changing location hash in browser address bar works, visiting /source/file.rb directly works Aman Gupta **20071125155740] [Fix doc/meta/users.kml for kml version 2.2 Michael Fellinger **20071125151618] [Cleanup proto: remove 'include Ramaze', require rubygems so ruby start.rb works, include :port option for easy changing Aman Gupta **20071125001957] [Add support for define_method actions with / instead of __ Aman Gupta **20071125001407] [Set Ramaze.start options when using ramaze binary Aman Gupta **20071125001027] [Add Symbol#/ to divide snippet Aman Gupta **20071124234554] [Fix breakage when trinity/response.rb is source reloaded Aman Gupta **20071122171300] [Use the almighty IPAddr to check for local IPs, _so_ _much_ _nicer_ and supports both IPv4 and IPv6 :D (is it obvious that i'm 10 minutes before a long weekend?) Michael Fellinger **20071122093614] [Calculate avg patches per day in patchsize rake task Aman Gupta **20071122091157] [Add String#unindent snippet and use it in Ramaise Aman Gupta **20071122081946] [This fixes some problems related to Request, better information on entering Action, fallback for Request#request_uri and fix Request#local_net? (damn you irb) Michael Fellinger **20071122074456] [Do go the usual Dispatcher::Action path when we encounter an error so Action::FILTER are applied. Michael Fellinger **20071122074255] [Adding Request#ip and Request#local_net? Michael Fellinger **20071122025741] [Fix Haml/Sass options handling Aman Gupta **20071122005737] [Wrap long lines in ramaise, don't include Ramaze in examples Aman Gupta **20071121204344] [Various hacks to get sourceview working in IE, some cleanups to reduce bandwidth and make page loads snappier Aman Gupta **20071121204013] [Add Ramaise example (Ramaze version of the Reprise hAtom blog) Aman Gupta **20071121080515] [Update README Michael Fellinger **20071121055247] [Simplify Thread.into + spec Aman Gupta **20071121034835] [Random minor spec cleanups Aman Gupta **20071121032643] [Use cache as a wrapper for value_cache when no args are provided Aman Gupta **20071120220219] [redirect_referrer on login in AuthHelper, a lot more useful and smoother Michael Fellinger **20071120085143] [Minor cleanups to sourceview example Aman Gupta **20071120080500] [Update allison raketask to use new version. Michael Fellinger **20071120042745] [keep darcs repo one step ahead on 0.2.1 Michael Fellinger **20071119163602] [TAG 0.2.0 Michael Fellinger **20071119161829] Patch bundle hash: fb16f453bc2a50f533f339c01315f42ee50207c2