apitest 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: []