restapi 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +0 -1
 - data/Gemfile.lock +0 -10
 - data/README.rdoc +18 -12
 - data/app/controllers/restapi/restapis_controller.rb +28 -1
 - data/app/views/layouts/restapi/restapi.html.erb +1 -0
 - data/app/views/restapi/restapis/_params.html.erb +22 -0
 - data/app/views/restapi/restapis/_params_plain.html.erb +16 -0
 - data/app/views/restapi/restapis/index.html.erb +5 -5
 - data/app/views/restapi/restapis/method.html.erb +8 -4
 - data/app/views/restapi/restapis/plain.html.erb +70 -0
 - data/app/views/restapi/restapis/resource.html.erb +16 -5
 - data/app/views/restapi/restapis/static.html.erb +4 -6
 - data/lib/restapi.rb +2 -1
 - data/lib/restapi/application.rb +72 -22
 - data/lib/restapi/client/generator.rb +104 -0
 - data/lib/restapi/client/template/Gemfile.tt +5 -0
 - data/lib/restapi/client/template/README.tt +3 -0
 - data/lib/restapi/client/template/base.rb.tt +33 -0
 - data/lib/restapi/client/template/bin.rb.tt +110 -0
 - data/lib/restapi/client/template/cli.rb.tt +25 -0
 - data/lib/restapi/client/template/cli_command.rb.tt +129 -0
 - data/lib/restapi/client/template/client.rb.tt +10 -0
 - data/lib/restapi/client/template/resource.rb.tt +17 -0
 - data/lib/restapi/dsl_definition.rb +20 -2
 - data/lib/restapi/error_description.rb +8 -2
 - data/lib/restapi/extractor.rb +143 -0
 - data/lib/restapi/extractor/collector.rb +113 -0
 - data/lib/restapi/extractor/recorder.rb +122 -0
 - data/lib/restapi/extractor/writer.rb +356 -0
 - data/lib/restapi/helpers.rb +10 -5
 - data/lib/restapi/markup.rb +12 -12
 - data/lib/restapi/method_description.rb +52 -8
 - data/lib/restapi/param_description.rb +6 -5
 - data/lib/restapi/railtie.rb +1 -1
 - data/lib/restapi/resource_description.rb +1 -1
 - data/lib/restapi/restapi_module.rb +43 -0
 - data/lib/restapi/validator.rb +70 -3
 - data/lib/restapi/version.rb +1 -1
 - data/lib/tasks/restapi.rake +120 -121
 - data/restapi.gemspec +0 -2
 - data/spec/controllers/restapis_controller_spec.rb +41 -6
 - data/spec/controllers/users_controller_spec.rb +51 -12
 - data/spec/dummy/app/controllers/application_controller.rb +0 -2
 - data/spec/dummy/app/controllers/twitter_example_controller.rb +4 -9
 - data/spec/dummy/app/controllers/users_controller.rb +13 -6
 - data/spec/dummy/config/initializers/restapi.rb +7 -0
 - data/spec/dummy/doc/restapi_examples.yml +28 -0
 - metadata +49 -76
 - data/app/helpers/restapi/restapis_helper.rb +0 -31
 
| 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # -*- coding: utf-8 -*-
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'thor'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'thor/group'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_support/inflector'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module Restapi
         
     | 
| 
      
 10 
     | 
    
         
            +
              module Client
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                class Generator < Thor::Group
         
     | 
| 
      
 13 
     | 
    
         
            +
                  include Thor::Actions
         
     | 
| 
      
 14 
     | 
    
         
            +
                  
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # Define arguments and options
         
     | 
| 
      
 16 
     | 
    
         
            +
                  argument :name
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_reader :doc, :resource
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(*args)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    super
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @doc = Restapi.to_json()[:docs]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def self.source_root
         
     | 
| 
      
 26 
     | 
    
         
            +
                    File.expand_path("../template", __FILE__)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end      
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def self.destination_root
         
     | 
| 
      
 30 
     | 
    
         
            +
                    File.join(FileUtils.pwd, "client")
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def self.start(client_name)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    super([client_name.parameterize.underscore], :destination_root => destination_root)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def generate_cli
         
     | 
| 
      
 38 
     | 
    
         
            +
                    template("README.tt", "README")
         
     | 
| 
      
 39 
     | 
    
         
            +
                    template("Gemfile.tt", "Gemfile")
         
     | 
| 
      
 40 
     | 
    
         
            +
                    template("bin.rb.tt", "bin/#{name}-client")
         
     | 
| 
      
 41 
     | 
    
         
            +
                    chmod("bin/#{name}-client", 0755)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    template("client.rb.tt", "lib/#{name}_client.rb")
         
     | 
| 
      
 43 
     | 
    
         
            +
                    template("base.rb.tt", "lib/#{name}_client/base.rb")
         
     | 
| 
      
 44 
     | 
    
         
            +
                    template("cli_command.rb.tt", "lib/#{name}_client/cli_command.rb")
         
     | 
| 
      
 45 
     | 
    
         
            +
                    doc[:resources].each do |key, resource|
         
     | 
| 
      
 46 
     | 
    
         
            +
                      @resource = resource
         
     | 
| 
      
 47 
     | 
    
         
            +
                      template("cli.rb.tt", "lib/#{name}_client/commands/#{resource_name}.thor")
         
     | 
| 
      
 48 
     | 
    
         
            +
                      template("resource.rb.tt", "lib/#{name}_client/resources/#{resource_name}.rb")
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  def class_base
         
     | 
| 
      
 55 
     | 
    
         
            +
                    name.camelize
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  def plaintext(text)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    text.gsub(/<.*?>/, '').gsub("\n",' ').strip
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  # Resource related helper methods:
         
     | 
| 
      
 63 
     | 
    
         
            +
                  
         
     | 
| 
      
 64 
     | 
    
         
            +
                  def resource_name
         
     | 
| 
      
 65 
     | 
    
         
            +
                    resource[:name].gsub(/\s/,"_").downcase.singularize
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  def api(method)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    method[:apis].first
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  def params_in_path(method)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    api(method)[:api_url].scan(/:([^\/]*)/).map(&:first)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  def client_args(method)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    client_args = params_in_path(method).dup
         
     | 
| 
      
 78 
     | 
    
         
            +
                    client_args << "params = {}" if method[:params].any?
         
     | 
| 
      
 79 
     | 
    
         
            +
                    client_args
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  def validation_hash(method)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    if method[:params].any? { |p| p[:params] }
         
     | 
| 
      
 84 
     | 
    
         
            +
                      method[:params].reduce({}) do |h, p|
         
     | 
| 
      
 85 
     | 
    
         
            +
                        h.update(p[:name] => (p[:params] ? p[:params].map { |pp| pp[:name] } : nil))
         
     | 
| 
      
 86 
     | 
    
         
            +
                      end
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      method[:params].map { |p| p[:name] }
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def substituted_url(method)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    params_in_path(method).reduce(api(method)[:api_url]) { |u, p| u.sub(":#{p}","\#{#{p}}")}
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  def transformation_hash(method)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    method[:params].find_all { |p| p[:expected_type] == "hash" && !p[:params].nil? }.reduce({}) do |h, p|
         
     | 
| 
      
 98 
     | 
    
         
            +
                      h.update(p[:name] => p[:params].map { |pp| pp[:name] })
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
                
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rest_client'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module <%= class_base %>Client
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :client
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(config)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @client =  RestClient::Resource.new(config[:base_url], :user => config[:username], :password => config[:password])
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def call(method, path, params = {})
         
     | 
| 
      
 13 
     | 
    
         
            +
                  ret = client[path].send(method, params)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  data = JSON.parse(ret.body) rescue ret.body
         
     | 
| 
      
 15 
     | 
    
         
            +
                  return data, ret
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def validate_params!(options, valid_keys)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  return unless options.is_a?(Hash)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  invalid_keys = options.keys - (valid_keys.is_a?(Hash) ? valid_keys.keys : valid_keys)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  raise ArgumentError, "Invalid keys: #{invalid_keys.join(", ")}" unless invalid_keys.empty?
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  if valid_keys.is_a? Hash
         
     | 
| 
      
 24 
     | 
    
         
            +
                    valid_keys.each do |key, keys|
         
     | 
| 
      
 25 
     | 
    
         
            +
                      if options[key]
         
     | 
| 
      
 26 
     | 
    
         
            +
                        validate_params!(options[key], keys)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,110 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "rubygems" # ruby1.9 doesn't "require" it though
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "pathname"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "thor"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'thor/core_ext/file_binary_read'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            $: << File.expand_path("../../lib", __FILE__)
         
     | 
| 
      
 8 
     | 
    
         
            +
            require "<%= name %>_client"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "<%= name %>_client/cli_command"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module <%= class_base %>Cli
         
     | 
| 
      
 12 
     | 
    
         
            +
              class Main < Thor
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def help(meth = nil)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if meth && !self.respond_to?(meth)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    initialize_thorfiles(meth)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    self.class.handle_no_task_error(task, false) if klass.nil?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    klass.start(["-h", task].compact, :shell => self.shell)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else
         
     | 
| 
      
 21 
     | 
    
         
            +
                    say "<%= name.capitalize %> CLI"
         
     | 
| 
      
 22 
     | 
    
         
            +
                    say
         
     | 
| 
      
 23 
     | 
    
         
            +
                    invoke :commands
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                desc "commands [SEARCH]", "List the available commands"
         
     | 
| 
      
 28 
     | 
    
         
            +
                def commands(search="")
         
     | 
| 
      
 29 
     | 
    
         
            +
                  initialize_thorfiles
         
     | 
| 
      
 30 
     | 
    
         
            +
                  klasses = Thor::Base.subclasses
         
     | 
| 
      
 31 
     | 
    
         
            +
                  display_klasses(false, false, klasses)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 35 
     | 
    
         
            +
                  private
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def dispatch(task, given_args, given_options, config)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    parser = Thor::Options.new({:username => Thor::Option.parse(%w[username -u], :string),
         
     | 
| 
      
 38 
     | 
    
         
            +
                                               :password => Thor::Option.parse(%w[password -p], :string)})
         
     | 
| 
      
 39 
     | 
    
         
            +
                    opts = parser.parse(given_args)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    <%= class_base %>Client.client_config[:username] = opts["username"]
         
     | 
| 
      
 41 
     | 
    
         
            +
                    <%= class_base %>Client.client_config[:password] = opts["password"]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    #remaining =  parser.instance_variable_get("@unknown") # TODO: this is an ugly hack :(
         
     | 
| 
      
 43 
     | 
    
         
            +
                    remaining = parser.remaining
         
     | 
| 
      
 44 
     | 
    
         
            +
                    super(task, remaining, given_options, config)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                private
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def method_missing(meth, *args)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  meth = meth.to_s
         
     | 
| 
      
 52 
     | 
    
         
            +
                  initialize_thorfiles(meth)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  args.unshift(task) if task
         
     | 
| 
      
 55 
     | 
    
         
            +
                  klass.start(args, :shell => self.shell)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                # Load the thorfiles. If relevant_to is supplied, looks for specific files
         
     | 
| 
      
 59 
     | 
    
         
            +
                # in the thor_root instead of loading them all.
         
     | 
| 
      
 60 
     | 
    
         
            +
                #
         
     | 
| 
      
 61 
     | 
    
         
            +
                # By default, it also traverses the current path until find Thor files, as
         
     | 
| 
      
 62 
     | 
    
         
            +
                # described in thorfiles. This look up can be skipped by suppliying
         
     | 
| 
      
 63 
     | 
    
         
            +
                # skip_lookup true.
         
     | 
| 
      
 64 
     | 
    
         
            +
                #
         
     | 
| 
      
 65 
     | 
    
         
            +
                def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  thorfiles.each do |f|
         
     | 
| 
      
 67 
     | 
    
         
            +
                    Thor::Util.load_thorfile(f, nil, options[:debug])
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def thorfiles
         
     | 
| 
      
 72 
     | 
    
         
            +
                  Dir[File.expand_path("../../lib/<%= name %>_client/commands/*.thor", __FILE__)]
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                # Display information about the given klasses. If with_module is given,
         
     | 
| 
      
 76 
     | 
    
         
            +
                # it shows a table with information extracted from the yaml file.
         
     | 
| 
      
 77 
     | 
    
         
            +
                #
         
     | 
| 
      
 78 
     | 
    
         
            +
                def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  klasses -= [Thor, Main, ::<%= class_base %>Client::CliCommand] unless show_internal
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  show_modules if with_modules && !thor_yaml.empty?
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  list = Hash.new { |h,k| h[k] = [] }
         
     | 
| 
      
 84 
     | 
    
         
            +
                  groups = []
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  # Get classes which inherit from Thor
         
     | 
| 
      
 87 
     | 
    
         
            +
                  (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_tasks(false) }
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # Get classes which inherit from Thor::Base
         
     | 
| 
      
 90 
     | 
    
         
            +
                  groups.map! { |k| k.printable_tasks(false).first }
         
     | 
| 
      
 91 
     | 
    
         
            +
                  list["root"] = groups
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  # Order namespaces with default coming first
         
     | 
| 
      
 94 
     | 
    
         
            +
                  list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
         
     | 
| 
      
 95 
     | 
    
         
            +
                  list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def display_tasks(namespace, list) #:nodoc:
         
     | 
| 
      
 99 
     | 
    
         
            +
                  say namespace
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            begin
         
     | 
| 
      
 106 
     | 
    
         
            +
              <%= class_base %>Cli::Main.start
         
     | 
| 
      
 107 
     | 
    
         
            +
            rescue RestClient::Exception => e
         
     | 
| 
      
 108 
     | 
    
         
            +
              $stderr.puts e.message
         
     | 
| 
      
 109 
     | 
    
         
            +
              exit 1
         
     | 
| 
      
 110 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class <%= resource_name.camelize %> < <%= class_base %>Client::CliCommand
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            <% resource[:methods].each do |method| -%>
         
     | 
| 
      
 4 
     | 
    
         
            +
              desc '<%= method[:name] %>', '<%= api(method)[:short_description] %>'
         
     | 
| 
      
 5 
     | 
    
         
            +
            <%   params_in_path(method).each do |param| -%>
         
     | 
| 
      
 6 
     | 
    
         
            +
              method_option :<%= param %>, :required => 'true'
         
     | 
| 
      
 7 
     | 
    
         
            +
            <%   end
         
     | 
| 
      
 8 
     | 
    
         
            +
                 method[:params].map {|p| p[:expected_type] == "hash" ? (p[:params] || p) : p}.flatten.each do |param| -%>
         
     | 
| 
      
 9 
     | 
    
         
            +
              method_option :<%= param[:name] %>, :required => <%= param[:required] ? 'true' : 'false' %>, :desc => '<%= plaintext(param[:description]) %>', :type => :<%= param[:expected_type] %>
         
     | 
| 
      
 10 
     | 
    
         
            +
            <%   end -%>
         
     | 
| 
      
 11 
     | 
    
         
            +
              def <%= method[:name] %>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <%   if params_in_path(method).any? || transformation_hash(method).any?
         
     | 
| 
      
 13 
     | 
    
         
            +
                   transform_options_params = [params_in_path(method).inspect]
         
     | 
| 
      
 14 
     | 
    
         
            +
                   transform_options_params << transformation_hash(method).inspect if transformation_hash(method).any? -%>
         
     | 
| 
      
 15 
     | 
    
         
            +
                <%= (params_in_path(method) + ["options"]).join(", ") %>, *_ = transform_options(<%= transform_options_params.join(", ").html_safe %>)
         
     | 
| 
      
 16 
     | 
    
         
            +
            <%   end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              client_args = params_in_path(method).dup
         
     | 
| 
      
 19 
     | 
    
         
            +
              client_args << "options" if method[:params].any? -%>
         
     | 
| 
      
 20 
     | 
    
         
            +
                data, resp = client.<%= method[:name] %><%= "(#{client_args.join(", ")})" if client_args.any? %>
         
     | 
| 
      
 21 
     | 
    
         
            +
                print_data(data)
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,129 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module <%= class_base %>Client
         
     | 
| 
      
 2 
     | 
    
         
            +
              class CliCommand < Thor
         
     | 
| 
      
 3 
     | 
    
         
            +
                no_tasks do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def client
         
     | 
| 
      
 5 
     | 
    
         
            +
                    resource_class = <%= class_base %>Client::Resources.const_get(self.class.name[/[^:]*$/])
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @client ||= resource_class.new(<%= class_base %>Client.client_config)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def transform_options(inline_params, transform_hash = {})
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ret = inline_params.map { |p| options[p] }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    # we use not mentioned params without change
         
     | 
| 
      
 13 
     | 
    
         
            +
                    transformed_options = (options.keys - transform_hash.values.flatten - inline_params).reduce({}) { |h, k| h.update(k => options[k]) }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    transform_hash.each do |sub_key, params|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      transformed_options[sub_key] = {}
         
     | 
| 
      
 17 
     | 
    
         
            +
                      params.each { |p| transformed_options[sub_key][p] = options[p] if options.has_key?(p) }
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    ret << transformed_options
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return *ret
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def print_data(data)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    case data
         
     | 
| 
      
 26 
     | 
    
         
            +
                    when Array
         
     | 
| 
      
 27 
     | 
    
         
            +
                      print_big_table(table_from_array(data))
         
     | 
| 
      
 28 
     | 
    
         
            +
                    when Hash
         
     | 
| 
      
 29 
     | 
    
         
            +
                      print_table(table_from_hash(data))
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      print_unknown(data)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  # unifies the data for further processing. e.g.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # 
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #     { "user" => {"username" => "test", "password" => "changeme" }
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # becomes:
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #     { "username" => "test", "password" => "changeme" }
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def normalize_item_data(item)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    if item.size == 1 && item.values.first.is_a?(Hash)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      item.values.first
         
     | 
| 
      
 45 
     | 
    
         
            +
                    else
         
     | 
| 
      
 46 
     | 
    
         
            +
                      item
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  def table_from_array(data)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    return [] if data.empty?
         
     | 
| 
      
 52 
     | 
    
         
            +
                    table = []
         
     | 
| 
      
 53 
     | 
    
         
            +
                    items = data.map { |item| normalize_item_data(item) }
         
     | 
| 
      
 54 
     | 
    
         
            +
                    columns = items.first.keys
         
     | 
| 
      
 55 
     | 
    
         
            +
                    table << columns
         
     | 
| 
      
 56 
     | 
    
         
            +
                    items.each do |item|
         
     | 
| 
      
 57 
     | 
    
         
            +
                      row = columns.map { |c| item[c] }
         
     | 
| 
      
 58 
     | 
    
         
            +
                      table << row.map(&:to_s)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    return table
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  def table_from_hash(data)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    return [] if data.empty?
         
     | 
| 
      
 65 
     | 
    
         
            +
                    table = []
         
     | 
| 
      
 66 
     | 
    
         
            +
                    normalize_item_data(data).each do |k, v|
         
     | 
| 
      
 67 
     | 
    
         
            +
                      table << ["#{k}:",v].map(&:to_s)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    table
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  def print_unknown(data)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    say data
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  def print_big_table(table, options={})
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return if table.empty?
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    formats, ident, colwidth = [], options[:ident].to_i, options[:colwidth]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    options[:truncate] = terminal_width if options[:truncate] == true
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    formats << "%-#{colwidth + 2}s" if colwidth
         
     | 
| 
      
 83 
     | 
    
         
            +
                    start = colwidth ? 1 : 0
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    start.upto(table.first.length - 2) do |i|
         
     | 
| 
      
 86 
     | 
    
         
            +
                      maxima ||= table.max{|a,b| a[i].size <=> b[i].size }[i].size
         
     | 
| 
      
 87 
     | 
    
         
            +
                      formats << "%-#{maxima + 2}s"
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    formats << "%s"
         
     | 
| 
      
 91 
     | 
    
         
            +
                    formats[0] = formats[0].insert(0, " " * ident)
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    header_printed = false
         
     | 
| 
      
 94 
     | 
    
         
            +
                    table.each do |row|
         
     | 
| 
      
 95 
     | 
    
         
            +
                      sentence = ""
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                      row.each_with_index do |column, i|
         
     | 
| 
      
 98 
     | 
    
         
            +
                        sentence << formats[i] % column.to_s
         
     | 
| 
      
 99 
     | 
    
         
            +
                      end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                      sentence = truncate(sentence, options[:truncate]) if options[:truncate]
         
     | 
| 
      
 102 
     | 
    
         
            +
                      $stdout.puts sentence
         
     | 
| 
      
 103 
     | 
    
         
            +
                      say(set_color("-" * sentence.size, :green)) unless header_printed
         
     | 
| 
      
 104 
     | 
    
         
            +
                      header_printed = true
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 111 
     | 
    
         
            +
                  def help(shell, subcommand = true)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    list = self.printable_tasks(true, subcommand)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    Thor::Util.thor_classes_in(self).each do |klass|
         
     | 
| 
      
 114 
     | 
    
         
            +
                      list += printable_tasks(false)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    list.sort!{ |a,b| a[0] <=> b[0] }
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    shell.say
         
     | 
| 
      
 119 
     | 
    
         
            +
                    shell.print_table(list, :indent => 2, :truncate => true)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    shell.say
         
     | 
| 
      
 121 
     | 
    
         
            +
                    Thor.send(:class_options_help, shell)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  def banner(task, namespace = nil, subcommand = false)
         
     | 
| 
      
 125 
     | 
    
         
            +
                    task.name
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
              end
         
     | 
| 
      
 129 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require '<%= name %>_client/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            resource_files = Dir[File.expand_path('../<%= name %>_client/resources/*.rb', __FILE__)]
         
     | 
| 
      
 4 
     | 
    
         
            +
            resource_files.each { |f| require f }
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module <%= class_base %>Client
         
     | 
| 
      
 7 
     | 
    
         
            +
              def self.client_config
         
     | 
| 
      
 8 
     | 
    
         
            +
                @client_config ||= {:base_url => "http://localhost:3000"}
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module <%= class_base %>Client
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Resources
         
     | 
| 
      
 3 
     | 
    
         
            +
                class <%= resource_name.camelize %> < <%= class_base %>Client::Base
         
     | 
| 
      
 4 
     | 
    
         
            +
            <% resource[:methods].each do |method| -%>
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def <%= method[:name] %><%= "(#{ client_args(method).join(", ") })" if client_args(method).any? %>
         
     | 
| 
      
 7 
     | 
    
         
            +
            <% if method[:params].any? -%>
         
     | 
| 
      
 8 
     | 
    
         
            +
                    validate_params!(params, <%= validation_hash(method).inspect.html_safe %>)
         
     | 
| 
      
 9 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 10 
     | 
    
         
            +
                    call(:<%= api(method)[:http_method].downcase %>, "<%= substituted_url(method) %>"<%= 
         
     | 
| 
      
 11 
     | 
    
         
            +
                    (api(method)[:http_method].downcase == 'get' ? ", :params => params" : ", params") if method[:params].any? %>)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     |