#!/usr/bin/env python # -*- coding: utf-8 -*- # Documentation for Mako templates: # http://www.makotemplates.org/docs/syntax.html import os, sys, re sys.path.append(os.path.join("vendor", "rabbitmq-codegen")) from amqp_codegen import * try: from mako.template import Template except ImportError: print "Mako isn't installed. Run easy_install mako." sys.exit(1) # main class class AmqpSpecObject(AmqpSpec): IGNORED_CLASSES = ["access"] IGNORED_FIELDS = { 'ticket': 0, 'capabilities': '', 'insist' : 0, 'out_of_band': '', 'known_hosts': '', } def __init__(self, path): AmqpSpec.__init__(self, path) def extend_field(field): field.ruby_name = re.sub("[- ]", "_", field.name) field.type = self.resolveDomain(field.domain) field.ignored = bool(field.name in self.__class__.IGNORED_FIELDS) # I. e. deprecated for klass in self.classes: klass.ignored = bool(klass.name in self.__class__.IGNORED_CLASSES) for field in klass.fields: extend_field(field) for method in klass.methods: for field in method.arguments: extend_field(field) self.classes = filter(lambda klass: not klass.ignored, self.classes) # I know, I'm a bad, bad boy, but come on guys, # monkey-patching is just handy for this case. # Oh hell, why Python doesn't have at least # anonymous functions? This looks so ugly. original_init = AmqpEntity.__init__ def new_init(self, arg): original_init(self, arg) constant_name = "" for chunk in self.name.split("-"): constant_name += chunk.capitalize() self.constant_name = constant_name AmqpEntity.__init__ = new_init # method.accepted_by("server") # method.accepted_by("client", "server") accepted_by_update = json.loads(file("amqp_0.9.1_changes.json").read()) def accepted_by(self, *receivers): def get_accepted_by(self): try: return accepted_by_update[self.klass.name][self.name] except KeyError: return ["server", "client"] actual_receivers = get_accepted_by(self) return all(map(lambda receiver: receiver in actual_receivers, receivers)) AmqpMethod.accepted_by = accepted_by def convert_value_to_ruby(value): values = {None: "nil", False: "false", True: "true", "": "EMPTY_STRING"} try: return values[value] except: return value.__repr__() def convert_to_ruby(field): name = re.sub("-", "_", field.name) # TODO: use ruby_name if name == "ticket": return "%s = %s" % (name, field.defaultvalue) # we want to keep it as an int, not as a boolean else: return "%s = %s" % (name, convert_value_to_ruby(field.defaultvalue)) def not_ignored_args(self): if self.hasContent: return ["payload", "user_headers"] + map(lambda argument: argument.ruby_name, filter(lambda argument: not argument.ignored, self.arguments)) + ["frame_size"] else: return map(lambda argument: argument.ruby_name, filter(lambda argument: not argument.ignored, self.arguments)) AmqpMethod.not_ignored_args = not_ignored_args def ignored_args(self): return filter(lambda argument: argument.ignored, self.arguments) AmqpMethod.ignored_args = ignored_args # helpers def to_ruby_name(name): return re.sub("[- ]", "_", name) def to_ruby_class_name(name): parts = re.split("[- ]", name) ruby_class_name = "" for part in parts: ruby_class_name = ruby_class_name + part[0].upper() + part[1:].lower() return ruby_class_name def params(self): buffer = [] for f in self.arguments: buffer.append(convert_to_ruby(f)) if self.hasContent: buffer.append("user_headers = nil") buffer.append("payload = \"\"") buffer.append("frame_size = nil") return buffer AmqpMethod.params = params def args(self): return map(lambda item: item.split(" ")[0], self.params()) AmqpMethod.args = args def binary(self): method_id = self.klass.index << 16 | self.index return "0x%08X # %i, %i, %i" % (method_id, self.klass.index, self.index, method_id) AmqpMethod.binary = binary # helpers def render(path, **context): file = open(path) template = Template(file.read()) return template.render(**context) def generateMain(type): def main(json_spec_path): spec = AmqpSpecObject(json_spec_path) spec.type = type print render("protocol.rb.pytemplate", spec = spec) return main if __name__ == "__main__": do_main_dict({"client": generateMain("client"), "server": generateMain("server")})