apitest 0.1.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2106d3cc53ccbac1df7e6001bea56f01120b1db8
4
+ data.tar.gz: 91547d4b2d5afea5e35d1e80462f7fa9fe3d131f
5
+ SHA512:
6
+ metadata.gz: 056ea12e6a741d65f266f1a413da52e7f383dc7da5b1601dbf5c1d83b3fe59d7c15b3b2bbd6b7fa0595971f2f7d66439567c4997d010133b43b43a4cc594c262
7
+ data.tar.gz: 3f5dbefb1dcf9d0398ac703172229d0aca1b398a94434b60446df93ddbd7e2c01e11831e7428dcd6552a9da44a6a923a54623ca3e5a91e69c5051bb986557e7d
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Kyuubi
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.md ADDED
@@ -0,0 +1,28 @@
1
+ # Apitest
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'apitest'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install apitest
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Apitest'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/apitest .js
2
+ //= link_directory ../stylesheets/apitest .css
@@ -0,0 +1,100 @@
1
+ # Place all the behaviors and hooks related to the matching controller here.
2
+ # All this logic will automatically be available in application.js.
3
+ # You can use CoffeeScript in this file: http://coffeescript.org/
4
+
5
+ #= require jquery3
6
+ #= require jquery_ujs
7
+ #= require turbolinks
8
+ #= require bootstrap
9
+ #= require adminlte/adminlte
10
+ #= require vue
11
+ #= require_directory .
12
+ #= require_self
13
+
14
+ $(document).on "turbolinks:load" , ->
15
+ if $('#apitest_show').length == 1
16
+ $('body').addClass('sidebar-collapse')
17
+ vm = new Vue
18
+ el : '#apitest_show'
19
+ data :
20
+ root_url : null
21
+ apis : null
22
+ ws : null
23
+ output_area : null
24
+ current_group : ''
25
+ current_api : ''
26
+ token : ''
27
+ apitest_tab_show : 'api_test'
28
+ mounted : ->
29
+ @apis = $('#data').data('apis')
30
+ @token = $('#data').data('token')
31
+ @output_area = $('#server-logs-output')
32
+ @root_url = $('#data').data('root-url')
33
+ @get_log()
34
+
35
+ methods :
36
+
37
+ group_select : (name) ->
38
+ @current_group = name
39
+ @current_api = ''
40
+
41
+ api_select : (name ) ->
42
+ @current_api = name
43
+
44
+ api_submit : (e) ->
45
+ elm = $(e.target).parents('.api')
46
+ result = elm.find('.result')
47
+ result_pre = elm.find('.result_pre')
48
+ path = elm.find('.path').val()
49
+ method = elm.find('.method').text()
50
+ postData = {}
51
+
52
+ elm.find('.params').each ->
53
+ postData[$(this).attr('name')] = $(this).val()
54
+
55
+ $.ajax
56
+ url : path
57
+ type : method
58
+ data : postData
59
+ success : (data) =>
60
+ # result.val JSON.stringify(data , null , 4)
61
+ result_pre.jsonViewer(data)
62
+ error : (data) =>
63
+ result.val data.responseText
64
+
65
+ clear_result : (e) ->
66
+ # $(e.target).parents('.api').find('.result').val('')
67
+ $(e.target).parents('.api').find('.result_pre').html('')
68
+
69
+ log_scroll : ->
70
+ $('#server-logs-output').scrollTop document.getElementById("server-logs-output").scrollHeight
71
+
72
+ get_log : (e) ->
73
+ unless @ws
74
+ @ws = new WebSocket($('#data').data('ws-url'))
75
+ @ws.onmessage = (evt) =>
76
+ $("<div>" + evt.data + "<div>").appendTo(@output_area)
77
+ @log_scroll()
78
+
79
+ $('#server-logs-output').height $('.api-wrap').height() - 104
80
+
81
+ clear_log : ->
82
+ $('#server-logs-output').html('')
83
+
84
+
85
+ show_api_test : ->
86
+ @apitest_tab_show = 'api_test'
87
+ show_server_log : ->
88
+ @apitest_tab_show = 'server_log'
89
+ @get_log()
90
+ $.AdminLTE.layout.fix() if $.AdminLTE.layout
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
@@ -0,0 +1,148 @@
1
+ /**
2
+ * jQuery json-viewer
3
+ * @author: Alexandre Bodelot <alexandre.bodelot@gmail.com>
4
+ */
5
+ (function($){
6
+
7
+ /**
8
+ * Check if arg is either an array with at least 1 element, or a dict with at least 1 key
9
+ * @return boolean
10
+ */
11
+ function isCollapsable(arg) {
12
+ return arg instanceof Object && Object.keys(arg).length > 0;
13
+ }
14
+
15
+ /**
16
+ * Check if a string represents a valid url
17
+ * @return boolean
18
+ */
19
+ function isUrl(string) {
20
+ var regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
21
+ return regexp.test(string);
22
+ }
23
+
24
+ /**
25
+ * Transform a json object into html representation
26
+ * @return string
27
+ */
28
+ function json2html(json, options) {
29
+ var html = '';
30
+ if (typeof json === 'string') {
31
+ // Escape tags
32
+ json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
33
+ if (isUrl(json))
34
+ html += '<a href="' + json + '" class="json-string">' + json + '</a>';
35
+ else
36
+ html += '<span class="json-string">"' + json + '"</span>';
37
+ }
38
+ else if (typeof json === 'number') {
39
+ html += '<span class="json-literal">' + json + '</span>';
40
+ }
41
+ else if (typeof json === 'boolean') {
42
+ html += '<span class="json-literal">' + json + '</span>';
43
+ }
44
+ else if (json === null) {
45
+ html += '<span class="json-literal">null</span>';
46
+ }
47
+ else if (json instanceof Array) {
48
+ if (json.length > 0) {
49
+ html += '[<ol class="json-array">';
50
+ for (var i = 0; i < json.length; ++i) {
51
+ html += '<li>'
52
+ // Add toggle button if item is collapsable
53
+ if (isCollapsable(json[i])) {
54
+ html += '<a href class="json-toggle"></a>';
55
+ }
56
+ html += json2html(json[i], options);
57
+ // Add comma if item is not last
58
+ if (i < json.length - 1) {
59
+ html += ',';
60
+ }
61
+ html += '</li>';
62
+ }
63
+ html += '</ol>]';
64
+ }
65
+ else {
66
+ html += '[]';
67
+ }
68
+ }
69
+ else if (typeof json === 'object') {
70
+ var key_count = Object.keys(json).length;
71
+ if (key_count > 0) {
72
+ html += '{<ul class="json-dict">';
73
+ for (var key in json) {
74
+ if (json.hasOwnProperty(key)) {
75
+ html += '<li>';
76
+ var keyRepr = options.withQuotes ?
77
+ '<span class="json-string">"' + key + '"</span>' : key;
78
+ // Add toggle button if item is collapsable
79
+ if (isCollapsable(json[key])) {
80
+ html += '<a href class="json-toggle">' + keyRepr + '</a>';
81
+ }
82
+ else {
83
+ html += keyRepr;
84
+ }
85
+ html += ': ' + json2html(json[key], options);
86
+ // Add comma if item is not last
87
+ if (--key_count > 0)
88
+ html += ',';
89
+ html += '</li>';
90
+ }
91
+ }
92
+ html += '</ul>}';
93
+ }
94
+ else {
95
+ html += '{}';
96
+ }
97
+ }
98
+ return html;
99
+ }
100
+
101
+ /**
102
+ * jQuery plugin method
103
+ * @param json: a javascript object
104
+ * @param options: an optional options hash
105
+ */
106
+ $.fn.jsonViewer = function(json, options) {
107
+ options = options || {};
108
+
109
+ // jQuery chaining
110
+ return this.each(function() {
111
+
112
+ // Transform to HTML
113
+ var html = json2html(json, options)
114
+ if (isCollapsable(json))
115
+ html = '<a href class="json-toggle"></a>' + html;
116
+
117
+ // Insert HTML in target DOM element
118
+ $(this).html(html);
119
+
120
+ // Bind click on toggle buttons
121
+ $(this).off('click');
122
+ $(this).on('click', 'a.json-toggle', function() {
123
+ var target = $(this).toggleClass('collapsed').siblings('ul.json-dict, ol.json-array');
124
+ target.toggle();
125
+ if (target.is(':visible')) {
126
+ target.siblings('.json-placeholder').remove();
127
+ }
128
+ else {
129
+ var count = target.children('li').length;
130
+ var placeholder = count + (count > 1 ? ' items' : ' item');
131
+ target.after('<a href class="json-placeholder">' + placeholder + '</a>');
132
+ }
133
+ return false;
134
+ });
135
+
136
+ // Simulate click on toggle button when placeholder is clicked
137
+ $(this).on('click', 'a.json-placeholder', function() {
138
+ $(this).siblings('a.json-toggle').click();
139
+ return false;
140
+ });
141
+
142
+ if (options.collapsed == true) {
143
+ // Trigger click to collapse all nodes
144
+ $(this).find('a.json-toggle').click();
145
+ }
146
+ });
147
+ };
148
+ })(jQuery);
@@ -0,0 +1,37 @@
1
+ // Place all the styles related to the apitest/v1 controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
4
+ //= require_directory .
5
+ //= require bootstrap
6
+ //= require adminlte/adminlte
7
+ //= require adminlte/skins/_all-skins
8
+ //= require font-awesome
9
+ //= require_self
10
+
11
+ #apitest_show{
12
+ #server-logs-output {
13
+ background-color: #444;
14
+ color: #ddd;
15
+ height: 794px;
16
+ overflow: scroll;
17
+ padding: 10px;
18
+ vertical-align: top;
19
+ }
20
+ .result{
21
+ resize: none;
22
+ }
23
+ .result_pre{
24
+ background-color: #fff;
25
+ height: 514px;
26
+ border-radius: 0px;
27
+ padding: 15px 30px 15px 30px;
28
+ }
29
+ .nav-pills.nav-stacked{
30
+ li.active {
31
+ a{
32
+ background-color: #337ab7;
33
+ color: #fff;
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,45 @@
1
+ /* Syntax highlighting for JSON objects */
2
+ ul.json-dict, ol.json-array {
3
+ list-style-type: none;
4
+ margin: 0 0 0 1px;
5
+ border-left: 1px dotted #ccc;
6
+ padding-left: 2em;
7
+ }
8
+ .json-string {
9
+ color: #0B7500;
10
+ }
11
+ .json-literal {
12
+ color: #1A01CC;
13
+ font-weight: bold;
14
+ }
15
+
16
+ /* Toggle button */
17
+ a.json-toggle {
18
+ position: relative;
19
+ color: inherit;
20
+ text-decoration: none;
21
+ }
22
+ a.json-toggle:focus {
23
+ outline: none;
24
+ }
25
+ a.json-toggle:before {
26
+ color: #aaa;
27
+ content: "\25BC"; /* down arrow */
28
+ position: absolute;
29
+ display: inline-block;
30
+ width: 1em;
31
+ left: -1em;
32
+ }
33
+ a.json-toggle.collapsed:before {
34
+ content: "\25B6"; /* left arrow */
35
+ }
36
+
37
+ /* Collapsable placeholder links */
38
+ a.json-placeholder {
39
+ color: #aaa;
40
+ padding: 0 1em;
41
+ text-decoration: none;
42
+ }
43
+ a.json-placeholder:hover {
44
+ text-decoration: underline;
45
+ }
@@ -0,0 +1,62 @@
1
+ require_dependency "apitest/application_controller"
2
+
3
+ module Apitest
4
+ class ApitestController < ApplicationController
5
+ before_action :get_doc
6
+ def index
7
+ respond_to do |format|
8
+ format.json { render json: @apidocs}
9
+ format.html
10
+ end
11
+ end
12
+
13
+ def show
14
+ respond_to do |format|
15
+ format.html
16
+ format.json { render json: @apidocs[params[:id]]}
17
+ end
18
+ end
19
+
20
+ private
21
+ def get_doc
22
+ path_root = "app/controllers/api/"
23
+ @apidocs = {}
24
+ Dir.glob("#{path_root}*").map do |path|
25
+ if File.directory?(path)
26
+ @apidocs[path.gsub("#{path_root}" , '')] = get_version_doc "#{path}/"
27
+ end
28
+ end
29
+ @root_url = main_app.root_url[0,main_app.root_url.length - 1]
30
+ end
31
+
32
+ def get_version_doc(path_root)
33
+
34
+ docs = {
35
+ '业务API' => [] ,
36
+ '工具API' => [] ,
37
+ '辅助API' => []
38
+ }
39
+ dirs = []
40
+ Dir.glob("#{path_root}*_controller.rb").each do |path|
41
+ controller_name_base = path.gsub(path_root , '').gsub('.rb' , '').singularize.camelize
42
+ controller_class = "Api::V1::#{controller_name_base}".constantize
43
+ if defined? controller_class::APIDOC
44
+ token_need = {
45
+ token: {
46
+ text: 'token' ,
47
+ required: true ,
48
+ }
49
+ }
50
+ doc = controller_class::APIDOC
51
+ doc[:sort] = 99 if doc[:sort].blank?
52
+ doc[:apis].each do |k,v|
53
+ doc[:apis][k][:params] = token_need.merge doc[:apis][k][:params] unless v[:token] == false
54
+ end
55
+ docs[doc[:type]] = [] if docs[doc[:type]].blank?
56
+ docs[doc[:type]].push doc
57
+ end
58
+ end
59
+ docs
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ module Apitest
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Apitest
2
+ module ApitestHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Apitest
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Apitest
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Apitest
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Apitest
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
File without changes
@@ -0,0 +1,92 @@
1
+ .content-header
2
+ h1 =params[:id].upcase
3
+ section.content
4
+ .col-sm-5.row
5
+ .groups v-bind:class="{hide: apitest_tab_show == 'server_log'}"
6
+ .col-sm-6
7
+ .box.box-primary v-for="(group_doc , group_name) in apis"
8
+ .box-header.with-border
9
+ h3.box-title ="{{group_name}}"
10
+ .box-tools
11
+ button.btn.btn-box-tool data-widget="collapse" type="button"
12
+ .fa.fa-minus
13
+ .box-body.no-padding
14
+ .nav.nav-pills.nav-stacked
15
+ li v-bind:class="{active: current_group == group.group_name , disabled: group.active == false}" v-for="group in group_doc"
16
+ a @click="group_select(group.group_name)" href="javascript:void(0)" ="{{group.group_name}}"
17
+
18
+ .col-sm-6 v-for="(group_doc , group_name) in apis"
19
+ .box.box-primary v-for="group in group_doc" v-bind:class="{hide: current_group != group.group_name}"
20
+ .box-header.with-border
21
+ h3.box-title ="{{group.group_name}}"
22
+ .box-body.no-padding
23
+ .nav.nav-pills.nav-stacked
24
+ li v-for="(api , name) in group.apis" v-bind:class="{active: current_group == group.group_name && current_api == name ,disabled: api.active == false}"
25
+ a @click="api_select(name)" href="javascript:void(0)"
26
+ .list-group-item-heading = "{{api.api_name}}"
27
+ .list-group-item-text = "{{api.path}}"
28
+
29
+ .col-sm-12
30
+ .box.box-danger.server-logs-wrap v-bind:class="{hide: apitest_tab_show == 'api_test'}"
31
+ .box-header.with-border
32
+ h4.box-title Server Logs
33
+ .box-body
34
+ #server-logs-output contenteditable='true'
35
+ .col-sm-7
36
+ .api-wrap
37
+ .row v-for="(group_doc , group_name) in apis"
38
+ .col-sm-12 v-for="group in group_doc" v-bind:class="{hide: current_group != group.group_name}"
39
+ .api v-for="(api , name) in group.apis" v-bind:class="{hide: current_api != name || current_group != group.group_name}"
40
+ .nav-tabs-custom
41
+ ul.nav.nav-tabs
42
+ li.api-wrap-tab @click="show_api_test" v-bind:class="{active: apitest_tab_show == 'api_test'}"
43
+ a href="javascript:void(0)" API Test
44
+ li.server-logs-warp-tab @click="show_server_log" v-bind:class="{active: apitest_tab_show == 'server_log'}"
45
+ a href="javascript:void(0)" Server Logs
46
+ .tab-content.no-padding
47
+ table.table
48
+ tbody
49
+ tr
50
+ td.col-md-2 style="border-top:none"
51
+ h4 API名称
52
+ td style="border-top:none"
53
+ h4 ="{{api.api_name}}"
54
+ tr
55
+ td url
56
+ td
57
+ input.form-control.url :value="root_url + api.path"
58
+ tr
59
+ td path
60
+ td
61
+ input.form-control.path :value="api.path"
62
+ tr
63
+ td 提交方式
64
+ td.method ="{{api.method}}"
65
+ tr
66
+ td 参数
67
+ td
68
+ table.table.table-hover.table-bordered
69
+ tr v-for="(value , name , index) in api.params"
70
+ td.col-md-2 v-bind:class="{'border-top-none': (index == 0)}"
71
+ span style="color:red;width:10px;display:inline-block"
72
+ span v-if="value.required" *
73
+ span ="{{name}}"
74
+ td v-if="name == 'token'" v-bind:class="{'border-top-none': index == 0}"
75
+ input.form-control.params :name="name" :value="token"
76
+ span style="line-height:25px" = "{{value.text}}"
77
+ td v-if="name != 'token'" v-bind:class="{'border-top-none': index == 0}"
78
+ input.form-control.params :name="name"
79
+ span style="line-height:25px" = "{{value.text}}"
80
+ tr
81
+ td
82
+ td
83
+ button.btn.bg-olive.btn-flat @click="api_submit" 提交
84
+ button.btn.bg-orange.btn-flat style="margin-left:10px;margin-right:10px" @click="clear_result" 清空结果
85
+ button.btn.bg-purple.btn-flat style="margin-left:10px;margin-right:10px" @click="show_server_log" 查看server log
86
+ button.btn.btn-warning.btn-flat style="margin-right:10px" @click="clear_log" 清空log
87
+ tr
88
+ td
89
+ td
90
+ pre.result_pre contenteditable='true'
91
+ / textarea.form-control.result rows="25"
92
+ .clearfix
@@ -0,0 +1,36 @@
1
+ doctype 5
2
+ html
3
+ head
4
+ title API TEST
5
+ = csrf_meta_tags
6
+ = stylesheet_link_tag 'apitest/application', 'data-turbolinks-track': 'reload' , media: 'all'
7
+ = javascript_include_tag 'apitest/application', 'data-turbolinks-track': 'reload'
8
+ body.hold-transition.skin-purple-light.sidebar-mini
9
+ .wrapper id="apitest_#{params[:action]}"
10
+ header.main-header
11
+ a.logo href="#{root_path}"
12
+ span.logo-mini T
13
+ span.logo-lg API TEST
14
+ .navbar.navbar-static-top role="navigation"
15
+ a.sidebar-toggle data-toggle="offcanvas" row="button" href="#"
16
+ span.sr-only Toggle navigation
17
+ aside.main-sidebar
18
+ section.sidebar
19
+ ul.sidebar-menu
20
+ li.treeview.active
21
+ a href="#"
22
+ i.fa.fa-code.text-purple
23
+ span API版本
24
+ ul.treeview-menu
25
+ -@apidocs.each do |version , apis|
26
+ li.treeview
27
+ a href="#{root_path}#{version}"
28
+ i.fa.fa-code-fork.text-purple
29
+ span =version.upcase
30
+ main.content-wrapper
31
+ =yield
32
+ footer.main-footer
33
+ -if params[:action] == 'show'
34
+ #data data-root-url="#{@root_url}" data-ws-url="ws://#{request.host}:9527" data-apis="#{@apidocs[params[:id]].to_json}" data-token="#{session[:token]}"
35
+
36
+
@@ -0,0 +1,33 @@
1
+ Process.detach(
2
+ fork do
3
+ p 'Kill Apitest WebSocket Process ...'
4
+ `lsof -i :9527 |awk '$1 == "ruby" {print $2}' |xargs kill -9`
5
+ begin
6
+ class Reader < EventMachine::FileTail
7
+ def initialize(path, startpos=-1, &block)
8
+ super(path, startpos)
9
+ @buffer = BufferedTokenizer.new
10
+ @block = block
11
+ end
12
+
13
+ def receive_data(data)
14
+ @buffer.extract(data).each { |line| @block.call(line) }
15
+ end
16
+ end
17
+
18
+ filename = "#{Rails.root}/log/#{Rails.env}.log"
19
+
20
+ EventMachine.run do
21
+ WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 9527) do |ws|
22
+ proc = Proc.new { |line|
23
+ ws.send Ansi::To::Html.new(line.strip).to_html.strip
24
+ }
25
+ EventMachine::file_tail(filename, Reader, &proc)
26
+ end
27
+ p 'Start Apitest WebSocket Process !'
28
+ end
29
+ rescue Exception => e
30
+ retry
31
+ end
32
+ end
33
+ )
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Apitest::Engine.routes.draw do
2
+ resources :apitest
3
+ root to: 'apitest#index'
4
+ get '/:id' , to: 'apitest#show'
5
+ end
@@ -0,0 +1,5 @@
1
+ module Apitest
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Apitest
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Apitest
2
+ VERSION = '0.1.2'
3
+ end
data/lib/apitest.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "apitest/engine"
2
+ require "slim-rails"
3
+ require "rails-adminlte"
4
+ require "vuejs-rails"
5
+ require "ansi-to-html"
6
+ require "font-awesome-rails"
7
+ require "ionicons-rails"
8
+ require 'eventmachine'
9
+ require 'eventmachine-tail'
10
+ require 'websocket-eventmachine-server'
11
+
12
+ module Apitest
13
+ # Your code goes here...
14
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :apitest do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,208 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apitest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Kyuubi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slim-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails-adminlte
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vuejs-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ansi-to-html
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: font-awesome-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ionicons-rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: eventmachine
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: eventmachine-tail
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: websocket-eventmachine-server
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: ''
154
+ email:
155
+ - kyuubi@chinacluster.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - MIT-LICENSE
161
+ - README.md
162
+ - Rakefile
163
+ - app/assets/config/apitest_manifest.js
164
+ - app/assets/javascripts/apitest/application.coffee
165
+ - app/assets/javascripts/apitest/jquery.json-viewer.js
166
+ - app/assets/stylesheets/apitest/application.scss
167
+ - app/assets/stylesheets/apitest/jquery.json-viewer.css
168
+ - app/controllers/apitest/apitest_controller.rb
169
+ - app/controllers/apitest/application_controller.rb
170
+ - app/helpers/apitest/apitest_helper.rb
171
+ - app/helpers/apitest/application_helper.rb
172
+ - app/jobs/apitest/application_job.rb
173
+ - app/mailers/apitest/application_mailer.rb
174
+ - app/models/apitest/application_record.rb
175
+ - app/views/apitest/apitest/index.slim
176
+ - app/views/apitest/apitest/show.slim
177
+ - app/views/layouts/apitest/application.slim
178
+ - config/initializers/apitest.rb
179
+ - config/routes.rb
180
+ - lib/apitest.rb
181
+ - lib/apitest/engine.rb
182
+ - lib/apitest/version.rb
183
+ - lib/tasks/apitest_tasks.rake
184
+ homepage: https://github.com/kyuubi9/apitest
185
+ licenses:
186
+ - MIT
187
+ metadata: {}
188
+ post_install_message:
189
+ rdoc_options: []
190
+ require_paths:
191
+ - lib
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ requirements: []
203
+ rubyforge_project:
204
+ rubygems_version: 2.6.8
205
+ signing_key:
206
+ specification_version: 4
207
+ summary: ''
208
+ test_files: []