calamum 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/calamum CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Author:: Mehrez Alachheb (<lachheb.mehrez@gmail.com>)
4
-
5
- $: << File.join(File.dirname(__FILE__), "..", "lib")
3
+ # Calamum is a simple REST API documentation generator.
4
+ # This is a fork, that allows you to work with JSON format.
5
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
6
6
 
7
7
  require 'rubygems'
8
8
  require 'calamum/runner'
data/lib/calamum.rb CHANGED
@@ -1,9 +1,15 @@
1
+ require 'erb'
2
+ require 'yajl'
1
3
  require 'yaml'
4
+ require 'fileutils'
2
5
  require 'pry'
3
- require 'erb'
4
- require 'active_model'
5
- require 'calamum/calamum_helper'
6
- require "calamum/version"
7
- require "calamum/config"
8
- require "calamum/definition_parser"
9
- require "calamum/request"
6
+
7
+ module Calamum
8
+ require 'calamum/config'
9
+ require 'calamum/helpers'
10
+ require 'calamum/resource'
11
+ require 'calamum/doc_parser'
12
+ require 'calamum/doc_generator'
13
+ require 'calamum/version'
14
+ VALID_TEMPLATES = %{twitter bootstrap}
15
+ end
@@ -1,13 +1,21 @@
1
1
  require 'calamum'
2
2
  require 'mixlib/config'
3
3
 
4
- module Calamum
5
- class Config
6
- extend Mixlib::Config
4
+ # Provides a class-based configuration object.
5
+ # See https://github.com/opscode/mixlib-config
6
+ class Calamum::Config
7
+ extend Mixlib::Config
7
8
 
8
- def self.inspect
9
- configuration.inspect
10
- end
9
+ def self.inspect
10
+ configuration.inspect
11
+ end
12
+
13
+ def self.apply(config)
14
+ merge!(config)
15
+
16
+ self.doc_path = File.join(config[:path], 'docs')
17
+ self.tpl_path = File.join(File.dirname(__FILE__), 'templates', config[:template])
18
+ raise "Unknown template #{config[:template]}" unless Calamum::VALID_TEMPLATES.include?(config[:template])
19
+ end
11
20
 
12
- end
13
21
  end
@@ -1,62 +1,33 @@
1
-
2
1
  class Calamum::DocGenerator
3
- include ERB::Util
4
- attr_accessor :resources, :template, :name, :url, :description
2
+ attr_accessor :template
5
3
 
6
- def initialize(template, resources, name, url, descr)
7
- @template = template
8
- @resources = resources
9
- @name = name
10
- @url = url
11
- @description = descr
12
- end
4
+ def initialize(tpl_name)
5
+ tpl_path = Calamum::Config[:tpl_path]
6
+ filename = "#{tpl_path}/#{tpl_name}.html.erb"
13
7
 
14
- def render()
15
- ERB.new(@template).result(binding)
8
+ @template = ERB.new(File.read(filename))
16
9
  end
17
10
 
18
- def self.load_template
19
- File.read(File.join(File.dirname(__FILE__), "templates", "bootstrap", "index.html.erb"))
20
- end
21
-
22
- def save_result(file)
23
- initialize_doc_dir
24
- File.open(file, "w+") do |f|
25
- f.write(render)
26
- end
27
- end
11
+ def self.init_base_dir
12
+ tpl_path = Calamum::Config[:tpl_path]
13
+ doc_path = Calamum::Config[:doc_path]
14
+ FileUtils.rm_r(doc_path, :force => true)
15
+ Dir.mkdir(doc_path)
28
16
 
29
- def initialize_doc_dir
30
- create_doc_dir
31
- Dir.mkdir File.join(Calamum::Config[:path], 'doc', 'assets')
32
- copy_assets
17
+ # copy assets from template directory
18
+ source = File.join(tpl_path, 'assets')
19
+ target = File.join(doc_path, 'assets')
20
+ FileUtils.copy_entry(source, target)
33
21
  end
34
22
 
35
- def copy_assets
36
- src = File.join(File.dirname(__FILE__), "templates", Calamum::Config[:template], "assets")
37
- dst = File.join(Calamum::Config[:path], 'doc', 'assets')
38
- begin
39
- FileUtils.copy_entry(src, dst)
40
- rescue => e
41
- puts_error e.message
23
+ def save_template(filename, values)
24
+ values.each do |k, v|
25
+ instance_variable_set("@#{k}", v)
42
26
  end
43
- end
44
27
 
45
- def create_doc_dir
46
- doc_dir = File.join(Calamum::Config[:path], 'doc')
47
- if File.exist?(doc_dir)
48
- while true
49
- print "The filename directoy #{doc_dir} already exists. Do you want to overwrite it? [Y/N]: "
50
- case $stdin.gets.chomp!.downcase
51
- when 'y'
52
- FileUtils.rm_r(doc_dir, :force => true)
53
- break
54
- when 'n'
55
- exit(1)
56
- end
57
- end
58
- end
59
- Dir.mkdir doc_dir
28
+ html_data = @template.result(binding)
29
+ filename = File.join(Calamum::Config[:doc_path], filename)
30
+ File.open(filename, 'w+') { |file| file.write(html_data) }
60
31
  end
61
32
 
62
33
  end
@@ -0,0 +1,49 @@
1
+ class Calamum::DocParser
2
+ attr_accessor :resources, :definition
3
+
4
+ def initialize(definition)
5
+ @resources = Hash.new
6
+ @definition = definition
7
+ end
8
+
9
+ def get_url
10
+ @definition['url']
11
+ end
12
+
13
+ def get_name
14
+ @definition['name']
15
+ end
16
+
17
+ def get_version
18
+ @definition['version']
19
+ end
20
+
21
+ def get_description
22
+ @definition['description']
23
+ end
24
+
25
+ def get_resources
26
+ Calamum::Config[:sort]? @definition['resources'].sort : @definition['resources']
27
+ end
28
+
29
+ def load_resources
30
+ get_resources.each do |name, methods|
31
+ list = []
32
+ methods.each do |resource|
33
+ if validate_resource?(resource)
34
+ list << Calamum::Resource.new(resource)
35
+ puts_info "#{resource['action']}: #{resource['uri']}"
36
+ else
37
+ puts_warning "Resource #{resource['action']}: #{resource['uri']} has incorrect definition"
38
+ end
39
+ end
40
+ @resources[name] = list if list.any?
41
+ end
42
+ @resources
43
+ end
44
+
45
+ def validate_resource?(resource)
46
+ resource['uri'] && resource['action'] && resource['description'] && %{GET POST PUT DELETE}.include?(resource['action'].upcase)
47
+ end
48
+
49
+ end
@@ -0,0 +1,31 @@
1
+ # Returns a formatted JSON string.
2
+ #
3
+ # @param json [String] JSON string to format
4
+ # @param indent [String] indent that used in formatting
5
+ # @return [String] prettier form of the given JSON string
6
+ def pj(json, indent = '&nbsp;')
7
+ require 'json'
8
+ JSON.pretty_generate(json, :indent => indent * 4).gsub!(/\n/, '<br/>')
9
+ end
10
+
11
+ # Output info message to console.
12
+ #
13
+ # @param msg [String] message to output
14
+ def puts_info(msg)
15
+ $stdout.puts "\e[32m[INFO] #{msg}\e[0m" if Calamum::Config[:debug]
16
+ end
17
+
18
+ # Output warning message to console.
19
+ #
20
+ # @param msg [String] message to output
21
+ def puts_warning(msg)
22
+ $stdout.puts "\e[33m[WARNING] #{msg}\e[0m" if Calamum::Config[:debug]
23
+ end
24
+
25
+ # Output error message to console.
26
+ #
27
+ # @param msg [String] message to output
28
+ def puts_error(msg)
29
+ $stderr.puts "\e[31m[ERROR] #{msg}\e[0m" if Calamum::Config[:debug]
30
+ exit(1)
31
+ end
@@ -0,0 +1,47 @@
1
+ # This class represents a single resource.
2
+ # It contains attributes from parsed definition.
3
+ # So anywhere in view template we can use this object.
4
+ class Calamum::Resource
5
+ attr_accessor :uri, :action, :headers,
6
+ :auth, :params, :errors, :description, :response
7
+
8
+ # Initialize object from attributes.
9
+ #
10
+ # @param attrs [Hash] attributes to set
11
+ def initialize(attrs)
12
+ @uri = attrs['uri']
13
+ @action = attrs['action'].upcase
14
+ @headers = attrs['headers'] || {}
15
+ @auth = !!attrs['authentication']
16
+ @params = attrs['params'] || {}
17
+ @errors = attrs['errors'] || {}
18
+ @description = attrs['description']
19
+ @response = attrs['response']
20
+ end
21
+
22
+ # @override
23
+ # Returns a string representing a label css class.
24
+ #
25
+ # @return [String] css class
26
+ def action_label
27
+ case @action
28
+ when 'GET'
29
+ 'label-info'
30
+ when 'POST'
31
+ 'label-success'
32
+ when 'PUT'
33
+ 'label-warning'
34
+ when 'DELETE'
35
+ 'label-important'
36
+ end
37
+ end
38
+
39
+ # @override
40
+ # Returns a string representing a resource.
41
+ #
42
+ # @return [String] resource in a form (action: uri)
43
+ def to_s
44
+ "#{action}: #{uri}"
45
+ end
46
+
47
+ end
@@ -3,89 +3,114 @@ require 'calamum/config'
3
3
  require 'calamum/doc_generator'
4
4
  require 'mixlib/cli'
5
5
 
6
+ # Provides a class-based command line opts.
7
+ # See https://github.com/opscode/mixlib-cli
6
8
  class Calamum::Runner
7
9
  include Mixlib::CLI
8
- CMD_NAME = "calamum"
9
-
10
- def initialize
11
- super
12
- end
13
10
 
14
11
  option :help,
15
- :short => "-h",
16
- :long => "--help",
17
- :description => "Show this message",
12
+ :short => '-h',
13
+ :long => '--help',
14
+ :description => 'Show this help',
18
15
  :on => :tail,
19
16
  :boolean => true,
20
17
  :show_options => true,
21
18
  :exit => 0
22
19
 
23
- option :version,
24
- :short => "-v",
25
- :long => "--version",
26
- :description => "Show #{CMD_NAME} version",
27
- :boolean => true,
28
- :proc => lambda {|v| puts "Calamum: #{Calamum::VERSION}"},
29
- :exit => 0
30
-
31
- option :debug,
32
- :short => "-d",
33
- :long => "--debug",
34
- :description => "Show actions to do (default)",
35
- :boolean => true,
36
- :default => true,
37
- :proc => lambda { |p| true }
38
-
39
- option :definition,
40
- :short => "-f DEFINITION",
41
- :long => "--file DEFINITION",
42
- :description => "Definition YAML file",
43
- :required => true
20
+ option :source,
21
+ :short => '-f DEFINITION',
22
+ :long => '--file DEFINITION',
23
+ :description => 'Path to the file with JSON API definition',
24
+ :required => true
44
25
 
45
26
  option :template,
46
- :short => "-t TEMPLATE",
47
- :long => "--template TEMPLATE",
48
- :description => "Documentation HTML template",
49
- :default => "bootstrap"
27
+ :short => '-t TEMPLATE',
28
+ :long => '--template TEMPLATE',
29
+ :description => 'Name of HTML template [twitter, bootstrap](twitter by default)',
30
+ :default => 'twitter'
50
31
 
51
32
  option :path,
52
- :short => "-p PATH",
53
- :long => "--path PATH",
54
- :description => "The distination path for the generated doc directory",
55
- :default => ENV['HOME']
33
+ :short => '-p PATH',
34
+ :long => '--path PATH',
35
+ :description => 'Path to the directory where docs will be generated',
36
+ :default => ENV['HOME']
56
37
 
38
+ option :debug,
39
+ :short => '-d',
40
+ :long => '--debug',
41
+ :description => 'Show actions to do (true by default)',
42
+ :default => true,
43
+ :boolean => true,
44
+ :proc => lambda { |x| true }
45
+
46
+ option :version,
47
+ :short => '-v',
48
+ :long => '--version',
49
+ :description => 'Show version number',
50
+ :proc => lambda { |x| puts Calamum::VERSION },
51
+ :exit => 0
52
+
57
53
  option :sort,
58
54
  :short => "-s",
59
55
  :long => "--sort",
60
56
  :description => "Sort the resources alphabetically",
61
57
  :boolean => true,
62
58
  :default => false
63
-
59
+
60
+ # Parses command line options and generates API documentation.
61
+ # See samples for details how to define meta-data for your API.
64
62
  def run
65
- load_options
66
- Calamum::Config.merge!(config)
67
- api_definition = load_definition_file
68
- @definition = Calamum::DefinitionParser.new(api_definition)
69
- @definition.load_requests
70
- template = Calamum::DocGenerator.load_template
71
- html_output = Calamum::DocGenerator.new(template,
72
- @definition.resources, @definition.get_name, @definition.get_url, @definition.get_description)
73
- html_output.save_result(File.join(Calamum::Config[:path], 'doc', 'index.html'))
63
+ parse_options
64
+ Calamum::Config.apply(config)
65
+ @definition = Calamum::DocParser.new(load_source)
66
+ @definition.load_resources
67
+ Calamum::DocGenerator.init_base_dir
68
+ process_index
69
+ process_pages if config[:template] == 'twitter'
70
+ rescue => ex
71
+ puts_error ex.message
74
72
  end
75
73
 
76
- def load_definition_file
77
- begin
78
- YAML.load(File.open(config[:definition]))
79
- rescue => e
80
- puts_error e.message
74
+ # Open and load the source file of api definition
75
+ def load_source
76
+ case File.extname(config[:source])
77
+ when '.json'
78
+ Yajl.load(File.open(config[:source]))
79
+ when '.yml'
80
+ YAML.load(File.open(config[:source]))
81
+ else
82
+ raise 'unknown source file extension'
81
83
  end
82
84
  end
85
+
86
+ # Bind values to index page and save it.
87
+ def process_index
88
+ bindings = {
89
+ :url => @definition.get_url,
90
+ :name => @definition.get_name,
91
+ :resources => @definition.resources,
92
+ :description => @definition.get_description,
93
+ :version => @definition.get_version
94
+ }
95
+
96
+ page = Calamum::DocGenerator.new(:index)
97
+ page.save_template('index.html', bindings)
98
+ end
99
+
100
+ # Bind values to view pages and save them.
101
+ def process_pages
102
+ bindings = {
103
+ :name => @definition.get_name,
104
+ :version => @definition.get_version
105
+ }
83
106
 
84
- def load_options
85
- begin
86
- parse_options
87
- rescue => e
88
- puts_error e.message
107
+ page = Calamum::DocGenerator.new(:view)
108
+ @definition.resources.each do |methods|
109
+ methods[1].each do |resource|
110
+ bindings.merge!(:resource => resource)
111
+ filename = "#{resource.object_id}.html"
112
+ page.save_template(filename, bindings)
113
+ end
89
114
  end
90
115
  end
91
116