amy 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +50 -0
- data/bin/amy +12 -0
- data/lib/amy/generate.rb +23 -0
- data/lib/amy/parser/defs.rb +25 -0
- data/lib/amy/parser/lexer.rb +118 -0
- data/lib/amy/parser/parser.rb +91 -0
- data/lib/amy/parser/tokens.rb +39 -0
- data/lib/amy/parser.rb +129 -0
- data/lib/amy/templates/main.rb +36 -0
- data/lib/amy.rb +8 -0
- data/views/js/amy.coffee +79 -0
- data/views/js/amy.js +301 -0
- data/views/js/amy.min.js +1 -0
- data/views/js/form.coffee +69 -0
- data/views/js/resource.coffee +57 -0
- data/views/js/utils.coffee +17 -0
- data/views/main.erb.html +40 -0
- data/views/style/style.css +444 -0
- metadata +205 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 84014c35977967c74c5d0cd3dc3f979ab252591e
|
4
|
+
data.tar.gz: 891c47801a0a669786da8792f57d9d5a46ea778f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5cec160b99dde0d735405afde3a379729cd153237afcee2dfa8e813e3ff00c3e0222ad472cda3cfb3a6a57efd5806570ea478a3f041deb498c978756fdeecf3e
|
7
|
+
data.tar.gz: d14dc381267e319f47cc016ba76b6936a7fa6ff6b0eec257b139c0c55334aa7c2a557f6f9c36070f2c8d1161e379206e60e1cef7709e0e093154e016a4b20bc6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Pere Urbon-Bayes
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Amy
|
2
|
+
|
3
|
+
![image](http://rachstick.files.wordpress.com/2012/04/amy-f.jpg)
|
4
|
+
|
5
|
+
Amy aims to be a documentation engine, something alike rdoc, but for REST APIs. With the motivation in mind to solve this situation, that has not much of options, specially in the ruby world.
|
6
|
+
|
7
|
+
With two mode of work, Amy can:
|
8
|
+
|
9
|
+
* Scrap a list of documentation files.
|
10
|
+
* Scrap your source code looking for special comments. ``Currently just works for sinatra``
|
11
|
+
|
12
|
+
and use this info to compose a nice website with your API docs.
|
13
|
+
|
14
|
+
At the documentation website you will be able to see the resources aggregated per each url pattern, and within them see each method, in a very REST way. In some cases, for the GET, HEAD and OPTIONS methods you will be able to run them and analise the output.
|
15
|
+
|
16
|
+
## I want to use it!
|
17
|
+
|
18
|
+
First of all, you've to understand this is in very pre alpha status, so everything can change in the near feature. But if you are still a brave man, you can take a look at [examples](examples) directory to see who to run this gem.
|
19
|
+
|
20
|
+
If you've a nice feature in mind, please submit a pull request, every contribution is wellcome.
|
21
|
+
|
22
|
+
To create the documentation website you've to run:
|
23
|
+
|
24
|
+
* ` amy [directory with the definitions] `
|
25
|
+
|
26
|
+
There is an option to create a ``.amy`` file in your main directory where you'll be able to tune a few options for the engine. Take a look at [.amy](.amy) for an example.
|
27
|
+
|
28
|
+
## TODO:
|
29
|
+
|
30
|
+
Next, and preatty obvious thing, is to write a decent documentation.
|
31
|
+
I've in mind also to extend the source code parsing capabilities to include:
|
32
|
+
* A better content management skills.
|
33
|
+
* Support for more web frameworks and programming languages.
|
34
|
+
|
35
|
+
and I'm sure many others will popup.
|
36
|
+
|
37
|
+
## Contributing to Amy
|
38
|
+
|
39
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
40
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
41
|
+
* Fork the project.
|
42
|
+
* Start a feature/bugfix branch.
|
43
|
+
* Commit and push until you are happy with your contribution.
|
44
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
45
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
46
|
+
|
47
|
+
## Copyright
|
48
|
+
|
49
|
+
Copyright (c) 2014 Pere Urbon-Bayes. See LICENSE.txt for further details.
|
50
|
+
|
data/bin/amy
ADDED
data/lib/amy/generate.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'amy/templates/main'
|
3
|
+
|
4
|
+
module Amy
|
5
|
+
class Generator
|
6
|
+
|
7
|
+
attr_reader :base_dir
|
8
|
+
|
9
|
+
def initialize(base_dir="doc/")
|
10
|
+
@base_dir = base_dir
|
11
|
+
end
|
12
|
+
|
13
|
+
def do(template, object)
|
14
|
+
Dir.mkdir(@base_dir) if (not File.exist?(@base_dir) or not File.directory?( @base_dir ))
|
15
|
+
ehtml = ERB.new(IO.read(template))
|
16
|
+
output = ehtml.result(object.get_binding)
|
17
|
+
File.open("#{@base_dir}#{object.path}", 'w') do |f|
|
18
|
+
f.write(output)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Parser
|
2
|
+
class Defs
|
3
|
+
|
4
|
+
attr_accessor :method, :url
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@props = {}
|
8
|
+
@method = ""
|
9
|
+
@url = ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_prop(key, text)
|
13
|
+
@props[key] = text
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_props
|
17
|
+
@props
|
18
|
+
end
|
19
|
+
|
20
|
+
def empty?
|
21
|
+
@props.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'amy/parser/tokens'
|
2
|
+
|
3
|
+
module Parser
|
4
|
+
class Lexer
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@filename = ""
|
8
|
+
@file = nil
|
9
|
+
@debug = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_debug(debug)
|
13
|
+
@debug = debug
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_input(file)
|
17
|
+
@filename = file
|
18
|
+
@file = File.new(file)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Get's the next token
|
23
|
+
#
|
24
|
+
def next
|
25
|
+
raise IOError.new("Stream is at the end of file.") if eof?
|
26
|
+
end_of_token = false
|
27
|
+
token = ""
|
28
|
+
while not end_of_token
|
29
|
+
c = @file.getc
|
30
|
+
puts "next c: #{c.inspect} v: #{valid_char?(c)} s: #{single_char?(c)} e: #{is_end_character?(c)}" if @debug
|
31
|
+
if eof? then
|
32
|
+
end_of_token = true
|
33
|
+
elsif (single_char?(c)) then
|
34
|
+
if (token.empty?) then
|
35
|
+
token = c
|
36
|
+
next_token = @file.getc
|
37
|
+
if ('#' == token and '#' == next_token) then
|
38
|
+
token << next_token
|
39
|
+
else
|
40
|
+
@file.seek(-1, IO::SEEK_CUR)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@file.seek(-1, IO::SEEK_CUR)
|
44
|
+
end
|
45
|
+
end_of_token = true
|
46
|
+
elsif (valid_char?(c)) then
|
47
|
+
token << c
|
48
|
+
elsif is_end_character?(c) then
|
49
|
+
move_till_next_token
|
50
|
+
end_of_token = (not token.empty?)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
puts "next" if @debug
|
54
|
+
build_token(token)
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Set's the lexer back to the begin
|
59
|
+
#
|
60
|
+
def rewind
|
61
|
+
@file.rewind
|
62
|
+
end
|
63
|
+
|
64
|
+
def eof?
|
65
|
+
@file.eof?
|
66
|
+
end
|
67
|
+
|
68
|
+
def lineno
|
69
|
+
@file.lineno
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def move_till_next_token
|
75
|
+
there = false
|
76
|
+
while not there
|
77
|
+
c = @file.getc
|
78
|
+
puts "move c:#{c.inspect} v: #{valid_char?(c)} s: #{single_char?(c)}" if @debug
|
79
|
+
if eof? then
|
80
|
+
there = true
|
81
|
+
elsif single_char?(c) or valid_char?(c) then
|
82
|
+
@file.seek(-1, IO::SEEK_CUR)
|
83
|
+
there = true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
puts "move" if @debug
|
87
|
+
end
|
88
|
+
|
89
|
+
def valid_char?(c)
|
90
|
+
not (c =~ /[[:alpha:]|[:digit:]|_|@|<|:|-]/).nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def single_char?(c)
|
94
|
+
not (c =~ /['|"|#|\/|\\|\[|\]|\.|\n]/).nil?
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
def is_white_space?(c)
|
99
|
+
not (c =~ /\s/).nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_end_character?(c)
|
103
|
+
eof? or single_char?(c) or !valid_char?(c)
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_token(token)
|
107
|
+
type = Tokens::STRING
|
108
|
+
if (token.start_with?("##"))
|
109
|
+
type = Tokens::COMMENT_TAG
|
110
|
+
elsif (token.start_with?("#"))
|
111
|
+
type = Tokens::COMMENT
|
112
|
+
elsif (token.start_with?("@"))
|
113
|
+
type = Tokens::PROPERTY
|
114
|
+
end
|
115
|
+
Token.new(type, token, @file.lineno)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'amy/parser/lexer'
|
2
|
+
require 'amy/parser/defs'
|
3
|
+
|
4
|
+
module Parser
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@lexer = Lexer.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(file)
|
12
|
+
@lexer.set_input(file)
|
13
|
+
parse_tokens(@lexer)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def parse_tokens(lexer)
|
19
|
+
defs = []
|
20
|
+
while(not lexer.eof?)
|
21
|
+
token = lexer.next
|
22
|
+
if token.is_ct? then
|
23
|
+
_def = parse_defs(lexer)
|
24
|
+
defs << _def unless _def.empty?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return defs
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_defs(lexer)
|
31
|
+
defs = Defs.new
|
32
|
+
return defs if (lexer.eof?)
|
33
|
+
finish = false
|
34
|
+
prop = ""
|
35
|
+
value = ""
|
36
|
+
mode = :normal
|
37
|
+
while (not lexer.eof? and not finish)
|
38
|
+
token = lexer.next
|
39
|
+
if :normal == mode and token.is_ct? then
|
40
|
+
set_property defs, prop, value
|
41
|
+
finish = true
|
42
|
+
elsif :content == mode and token.is_p? and "@end" == token.value then
|
43
|
+
mode = :normal
|
44
|
+
set_property defs, prop, value
|
45
|
+
elsif prop.empty? and token.is_p? then
|
46
|
+
prop = token.value
|
47
|
+
mode = :content if "@content" == prop
|
48
|
+
elsif not prop.empty? and token.is_p? then
|
49
|
+
set_property defs, prop, value
|
50
|
+
prop = token.value
|
51
|
+
value = ""
|
52
|
+
mode = :content if "@content" == prop
|
53
|
+
elsif not prop.empty? and token.is_s? then
|
54
|
+
value << " #{token.value}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
lexer.next
|
58
|
+
defs.method = lexer.next.value
|
59
|
+
finish = false
|
60
|
+
lexer.next
|
61
|
+
while(not lexer.eof? and not finish)
|
62
|
+
token = lexer.next
|
63
|
+
if ["'", '"'].include?(token.value) then
|
64
|
+
finish = true
|
65
|
+
else
|
66
|
+
defs.url << token.value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return defs
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_property(defs, prop, value)
|
73
|
+
if ("@params" == prop) then
|
74
|
+
params = {}
|
75
|
+
fields = value.split(" ")
|
76
|
+
last_key = ""
|
77
|
+
fields.each_with_index do |field, i|
|
78
|
+
if (i%2 == 0) then
|
79
|
+
last_key = field
|
80
|
+
else
|
81
|
+
params[last_key] = field
|
82
|
+
last_key = ""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
defs.add_prop prop, params
|
86
|
+
else
|
87
|
+
defs.add_prop prop, value.strip
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Parser
|
2
|
+
|
3
|
+
module Tokens
|
4
|
+
STRING = 'string'
|
5
|
+
COMMENT_TAG = 'comment_tag'
|
6
|
+
COMMENT = 'comment'
|
7
|
+
PROPERTY = 'property'
|
8
|
+
TEXT = 'text'
|
9
|
+
end
|
10
|
+
|
11
|
+
class Token
|
12
|
+
attr_accessor :type, :value, :lineno
|
13
|
+
def initialize(type, value, lineno)
|
14
|
+
@type = type
|
15
|
+
@value = value
|
16
|
+
@lineno = lineno
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_ct?
|
20
|
+
Tokens::COMMENT_TAG == @type
|
21
|
+
end
|
22
|
+
def is_c?
|
23
|
+
Tokens::COMMENT == @type or Tokens::COMMENT_TAG == @type
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_p?
|
27
|
+
Tokens::PROPERTY == @type
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_s?
|
31
|
+
Tokens::STRING == @type
|
32
|
+
end
|
33
|
+
|
34
|
+
def is_a?(type)
|
35
|
+
@type == type
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/lib/amy/parser.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'maruku'
|
3
|
+
require 'amy/parser/parser'
|
4
|
+
|
5
|
+
module Amy
|
6
|
+
class Parser
|
7
|
+
|
8
|
+
OPTIONS_FILE = ".amy"
|
9
|
+
|
10
|
+
def initialize(base_dir = "doc/")
|
11
|
+
@generator = Amy::Generator.new base_dir
|
12
|
+
@options = load_options_file
|
13
|
+
@mode = @options['mode'] || 'file'
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'pp'
|
17
|
+
|
18
|
+
def execute(dir)
|
19
|
+
specs = load_specs dir
|
20
|
+
if (@mode == "code")
|
21
|
+
specs['links'] = @options['links']
|
22
|
+
specs['base_url'] = @options['base_url']
|
23
|
+
specs['api_version'] = @options['api_version']
|
24
|
+
end
|
25
|
+
compile_json_specs_with dir, specs
|
26
|
+
generate_main_page_with specs
|
27
|
+
copy_styles_and_js
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def compile_json_specs_with(dir, specs)
|
34
|
+
specs['resources'].each_pair { |resource, options|
|
35
|
+
resource_spec = JSON.parse(IO.read(File.join(File.join(dir, options['dir']),"resource.def")))
|
36
|
+
options['config'] = build_resource File.join(dir, options['dir']), resource_spec
|
37
|
+
} if (@mode == "file")
|
38
|
+
File.open("#{Amy::BASE_DIR}/views/js/data.json", 'w') do |f|
|
39
|
+
f.write(specs.to_json)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_resource(dir, specs)
|
44
|
+
resources = Dir.new(dir)
|
45
|
+
to_skip = [ '.', '..', 'resource.def' ]
|
46
|
+
record = specs['config']
|
47
|
+
resources.entries.each do |entry|
|
48
|
+
next if to_skip.include?(entry)
|
49
|
+
content = IO.read File.join(resources.path, entry)
|
50
|
+
method = File.basename(entry, File.extname(entry)).upcase
|
51
|
+
doc = Maruku.new(content)
|
52
|
+
record[method.downcase]['content'] = doc.to_html
|
53
|
+
end
|
54
|
+
record
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_main_page_with(specs)
|
58
|
+
main_page = Amy::Model::Main.new
|
59
|
+
specs['resources'].each_pair { |resource, options|
|
60
|
+
main_page.add_resource( { 'resource' => resource, 'title' => options['title'] } )
|
61
|
+
}
|
62
|
+
main_page.set_links specs['links'] || []
|
63
|
+
main_page.set_version specs['api_version']
|
64
|
+
main_page.set_base_url specs['base_url']
|
65
|
+
@generator.do("#{Amy::BASE_DIR}/views/main.erb.html", main_page)
|
66
|
+
end
|
67
|
+
|
68
|
+
def load_specs(dir)
|
69
|
+
if "file" == @mode then
|
70
|
+
JSON.parse(IO.read(File.join(dir,"/specs.def")))
|
71
|
+
elsif "code" == @mode then
|
72
|
+
{ 'resources' => parse_source_code(dir) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_source_code(dir)
|
77
|
+
parser = ::Parser::Parser.new
|
78
|
+
data = {}
|
79
|
+
Dir.foreach(dir) do |file|
|
80
|
+
next if [".", ".."].include?(file)
|
81
|
+
path = File.join(dir, file)
|
82
|
+
if (File.directory?(path)) then
|
83
|
+
parse_source_code(path).each_pair do |key, val|
|
84
|
+
if data[key].nil? then
|
85
|
+
data[key] = val
|
86
|
+
else
|
87
|
+
data[key].merge!(val)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
else
|
91
|
+
defs = parser.parse(path)
|
92
|
+
if not defs.empty? then
|
93
|
+
defs.each do |_def|
|
94
|
+
data[_def.url] = { 'title' => '', 'config' => {} } if data[_def.url].nil?
|
95
|
+
record = { 'url' => _def.url, 'title' => _def.get_props["@title"], 'content' => '' }
|
96
|
+
if _def.get_props['@params'] then
|
97
|
+
record['params'] = []
|
98
|
+
_def.get_props['@params'].each_pair do |k,v|
|
99
|
+
record['params'] << [k,v]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
record['content'] = _def.get_props['@content'].gsub(/\n/,'<br/>') if _def.get_props['@content']
|
103
|
+
if _def.get_props['@description'] then
|
104
|
+
data[_def.url]['title'] = _def.get_props['@description']
|
105
|
+
end
|
106
|
+
data[_def.url]['config'][_def.method] = record
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return data
|
112
|
+
end
|
113
|
+
|
114
|
+
def copy_styles_and_js
|
115
|
+
base_dir = @generator.base_dir
|
116
|
+
Dir.mkdir("#{base_dir}/js")
|
117
|
+
FileUtils.cp("#{Amy::BASE_DIR}/views/js/amy.min.js", "#{base_dir}/js/amy.js")
|
118
|
+
FileUtils.cp("#{Amy::BASE_DIR}/views/js/data.json", "#{base_dir}/data.json")
|
119
|
+
Dir.mkdir("#{base_dir}/style")
|
120
|
+
FileUtils.cp("#{Amy::BASE_DIR}/views/style/style.css", "#{base_dir}/style/style.css")
|
121
|
+
end
|
122
|
+
|
123
|
+
def load_options_file
|
124
|
+
return {} unless File.exist?(OPTIONS_FILE)
|
125
|
+
YAML::load(File.open(OPTIONS_FILE))
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Amy::Model
|
2
|
+
|
3
|
+
class Main
|
4
|
+
|
5
|
+
attr_reader :path
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@resources = []
|
9
|
+
@apiversion = ""
|
10
|
+
@base_url = ""
|
11
|
+
@links = []
|
12
|
+
@path = 'index.html'
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_resource(resource)
|
16
|
+
@resources << resource
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_links(links=[])
|
20
|
+
@links = links
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_version(version)
|
24
|
+
@apiversion = version
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_base_url(base_url)
|
28
|
+
@base_url = base_url
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_binding
|
32
|
+
binding
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/amy.rb
ADDED
data/views/js/amy.coffee
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
class Tabelle
|
2
|
+
|
3
|
+
constructor: ->
|
4
|
+
return
|
5
|
+
|
6
|
+
setup: (url) ->
|
7
|
+
self = this
|
8
|
+
request_config =
|
9
|
+
url: url+"?date="+(new Date()).getTime()
|
10
|
+
type: "GET"
|
11
|
+
dataType: "json"
|
12
|
+
success: (data) ->
|
13
|
+
$('.resources div').remove()
|
14
|
+
i = 0
|
15
|
+
for resource,config of data['resources']
|
16
|
+
resource = self.add_resource(resource, config, i, data['base_url'])
|
17
|
+
resource.toggle()
|
18
|
+
i++
|
19
|
+
self.add_resource_events(data)
|
20
|
+
self.toggle_method_if_necessary()
|
21
|
+
error: (e) ->
|
22
|
+
$('.resources div').remove()
|
23
|
+
$.ajax request_config
|
24
|
+
return
|
25
|
+
|
26
|
+
add_resource: (name, resource, i, base_url="") ->
|
27
|
+
resource = new Resource(name, resource, i, base_url)
|
28
|
+
resource.build()
|
29
|
+
return resource
|
30
|
+
|
31
|
+
add_resource_events: (data) ->
|
32
|
+
handlerIn = () ->
|
33
|
+
$(this).css("background", "#f5f5f5")
|
34
|
+
$(this).children('div').children().css('color', 'black')
|
35
|
+
return
|
36
|
+
handlerOut = () ->
|
37
|
+
$(this).css("background", "#fff")
|
38
|
+
$(this).children('div').children().css('color', '#999')
|
39
|
+
return
|
40
|
+
$(".resource").hover(handlerIn, handlerOut)
|
41
|
+
$('.resource').click ->
|
42
|
+
event.stopPropagation()
|
43
|
+
$(this).next().fadeToggle()
|
44
|
+
return
|
45
|
+
return
|
46
|
+
|
47
|
+
toggle_method_if_necessary: ->
|
48
|
+
anchor = window.location.hash.replace('!','')
|
49
|
+
anchor = anchor.replace(/\//g,"\\/")
|
50
|
+
anchor = anchor.replace(/:/g,'\\:')
|
51
|
+
fields = anchor.split('#')
|
52
|
+
$("#"+fields[1]+" + div .method."+fields[2]+" .content").fadeToggle()
|
53
|
+
$("#"+fields[1]+" + div .method."+fields[2]+" .form").fadeToggle()
|
54
|
+
$("#"+fields[1]).next().fadeToggle()
|
55
|
+
return
|
56
|
+
|
57
|
+
@toggleMethods: (i) ->
|
58
|
+
event.stopPropagation()
|
59
|
+
$("#resource#{i}").fadeToggle()
|
60
|
+
return
|
61
|
+
@showJSON: ->
|
62
|
+
event.stopPropagation()
|
63
|
+
url = $("#selector #key").val()
|
64
|
+
window.open(url, "_self") if url
|
65
|
+
return
|
66
|
+
|
67
|
+
window.toggleMethods = Tabelle.toggleMethods
|
68
|
+
window.showJSON = Tabelle.showJSON
|
69
|
+
|
70
|
+
$(document).ready ->
|
71
|
+
tabelle = new Tabelle
|
72
|
+
utils = new Utils
|
73
|
+
utils.toggle_by_class 'content'
|
74
|
+
url = utils.default_config_url()
|
75
|
+
$('#header #selector input').val(url)
|
76
|
+
tabelle.setup(url)
|
77
|
+
$('#header #explore').click ->
|
78
|
+
tabelle.setup($('#header #selector input').val())
|
79
|
+
return
|