riddick 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ module Riddick
2
+ def self.version
3
+ '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,96 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Welcome to Riddick!</title>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <!--[if IE ]><meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"><![endif]-->
8
+ <!--[if lt IE 9]>
9
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
10
+ <![endif]-->
11
+ <link href="<%= url 'stylesheets/vendor/bootstrap.css' %>" media="all" rel="stylesheet" type="text/css">
12
+ <link href="<%= url 'stylesheets/vendor/bootstrap-responsive.css' %>" media="all" rel="stylesheet" type="text/css">
13
+ <link href="<%= url 'stylesheets/vendor/chosen.css' %>" media="all" rel="stylesheet" type="text/css">
14
+ <link href="<%= url 'stylesheets/riddick.css' %>" media="all" rel="stylesheet" type="text/css">
15
+ </head>
16
+
17
+ <body>
18
+ <div class="container">
19
+ <div class="navbar">
20
+ <div class="navbar-inner">
21
+ <a href="<%= root_url %>" class="brand">Riddick</a>
22
+ <ul class="nav">
23
+ <li class="<%= 'active' if request.path == root_url %>">
24
+ <a href="<%= root_url %>">All translations</a>
25
+ </li>
26
+ <li class="<%= 'active' if request.path == my_url %>">
27
+ <a href="<%= my_url %>">My translations</a>
28
+ </li>
29
+ <li class="<%= 'active' if request.path == default_url %>">
30
+ <a href="<%= default_url %>">Default translations</a>
31
+ </li>
32
+ </ul>
33
+ </div>
34
+ </div>
35
+
36
+ <form action="<%= set_url %>" method="post" class="form-horizontal well">
37
+ <select name="k" data-chosen="chosen" data-for="textarea[name=v]" data-placeholder="en.greeting">
38
+ <option></option>
39
+ <% @translations.each do |k, v| %>
40
+ <option value="<%= k %>" data-v='<%= v %>'><%= k %></option>
41
+ <% end %>
42
+ </select>
43
+ <button type="submit" class="btn btn-success">Change</button><br />
44
+ <textarea name="v" type="text" placeholder="Hello World!"></textarea>
45
+ </form>
46
+
47
+ <% [:flash_success, :flash_error].each do |k| %>
48
+ <% if v = session.delete(k) %>
49
+ <div class="alert alert-<%= k.to_s.gsub 'flash_', '' %>"><%= v %></div>
50
+ <% end %>
51
+ <% end %>
52
+
53
+ <% if @translations.any? %>
54
+ <table class="table table-striped">
55
+ <tr><th>Path</th><th>Translation</th><th>Actions</th></tr>
56
+ <% @translations.each_pair do |k, v| %>
57
+ <tr>
58
+ <% if v.kind_of? Riddick::Backends::KeyValue::Value %>
59
+ <td><span class="badge badge-success"><%= k %></span></td>
60
+ <td><code>
61
+ <a rel="popover" data-title="My translation" data-content='<%= v %>'
62
+ data-trigger="hover"><%= truncate v %></a>
63
+ </code></td>
64
+ <td>
65
+ <a href="#custom-translations" data-choose="<%= k %>" data-v='<%= v %>'
66
+ class="btn btn-mini">Edit</a>
67
+ <a href="<%= del_url k %>" data-confirm="Are you sure?"
68
+ class="btn btn-mini btn-danger">Delete</a>
69
+ </td>
70
+ <% else %>
71
+ <td><span class="badge"><%= k %></span></td>
72
+ <td><code>
73
+ <a rel="popover" data-title="Default translation" data-content='<%= v %>'
74
+ data-trigger="hover"><%= truncate v %></a>
75
+ </code></td>
76
+ <td>
77
+ <a href="#custom-translations" data-choose="<%= k %>" data-v='<%= v %>'
78
+ class="btn btn-mini">Edit</a>
79
+ </td>
80
+ <% end %>
81
+ </tr>
82
+ <% end %>
83
+ </table>
84
+ <% else %>
85
+ <div class="alert alert-info">You have no translations yet.</div>
86
+ <% end %>
87
+
88
+ <div class="well"><a href="https://github.com/kostia/riddick">https://github.com/kostia/riddick</a></div>
89
+ </div>
90
+
91
+ <script src="<%= url 'javascripts/vendor/jquery.js' %>" type="text/javascript"></script>
92
+ <script src="<%= url 'javascripts/vendor/chosen.js' %>" type="text/javascript"></script>
93
+ <script src="<%= url 'javascripts/vendor/bootstrap.js' %>" type="text/javascript"></script>
94
+ <script src="<%= url 'javascripts/riddick.js' %>" type="text/javascript"></script>
95
+ </body>
96
+ </html>
@@ -0,0 +1,27 @@
1
+ require File.expand_path '../lib/riddick/version', __FILE__
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'riddick'
5
+ gem.version = Riddick.version
6
+ gem.description = %{
7
+ Riddick is a simple Sintra based GUI for Redis-I18n-backend.
8
+ It provides a list of preconfigured translations (via YAML-backend).
9
+ Also you can add your translations to Redis-backend.
10
+ }
11
+ gem.summary = 'Simple GUI for Redis-I18n-backend'
12
+ gem.homepage = 'https://github.com/kostia/riddick'
13
+ gem.authors = ['Kostiantyn Kahanskyi']
14
+ gem.email = %w[kostiantyn.kahanskyi@googlemail.com]
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.require_paths = %w[lib]
17
+ gem.required_ruby_version = '>= 1.9.3'
18
+ gem.add_dependency 'i18n'
19
+ gem.add_dependency 'redis'
20
+ gem.add_dependency 'sinatra'
21
+ gem.add_development_dependency 'capybara'
22
+ gem.add_development_dependency 'pry'
23
+ gem.add_development_dependency 'rack-test'
24
+ gem.add_development_dependency 'rake'
25
+ gem.add_development_dependency 'rspec'
26
+ gem.add_development_dependency 'yajl-ruby'
27
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riddick::Backends::KeyValue do
4
+ describe 'creating a new backend' do
5
+ it 'should store i18n backend' do
6
+ i18n_be = mock
7
+ Riddick::Backends::KeyValue.new(i18n_be).i18n_backend.should == i18n_be
8
+ end
9
+ end
10
+
11
+ describe Riddick::Backends::KeyValue::Value do
12
+ it 'should return decoded string' do
13
+ v = Riddick::Backends::KeyValue::Value.new MultiJson.encode('foo')
14
+ v.to_s.should == 'foo'
15
+
16
+ v = Riddick::Backends::KeyValue::Value.new MultiJson.encode(%w[foo bar baz])
17
+ v.to_s.should == '["foo", "bar", "baz"]'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riddick::Backends::Redis do
4
+ describe 'creating a new backend' do
5
+ it 'should be a key value backend' do
6
+ Riddick::Backends::Redis.new(mock).should be_kind_of(Riddick::Backends::KeyValue)
7
+ end
8
+
9
+ it 'should store i18n backend' do
10
+ i18n_be = mock
11
+ Riddick::Backends::Redis.new(i18n_be).i18n_backend.should == i18n_be
12
+ end
13
+ end
14
+
15
+ describe '#translations' do
16
+ describe 'if there are any keys' do
17
+ it 'should return the translation hash' do
18
+ redis_be = mock(store: mock(keys: %w[k1 k2 k3]))
19
+ redis_be.store.should_receive(:mget).with(%w[k1 k2 k3]).and_return %w["v1" "v2" "v3"]
20
+ translations = Riddick::Backends::Redis.new(redis_be).translations
21
+ translations.size.should == 3
22
+ translations['k1'].should be_a(Riddick::Backends::Redis::Value)
23
+ translations['k1'].to_s.should == 'v1'
24
+ translations['k2'].should be_a(Riddick::Backends::Redis::Value)
25
+ translations['k2'].to_s.should == 'v2'
26
+ translations['k3'].should be_a(Riddick::Backends::Redis::Value)
27
+ translations['k3'].to_s.should == 'v3'
28
+ end
29
+ end
30
+
31
+ describe 'if there are no keys' do
32
+ it 'should return an empty hash' do
33
+ redis_be = mock(store: mock(keys: []))
34
+ Riddick::Backends::Redis.new(redis_be).translations.should == {}
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#delete_translation' do
40
+ it 'should delete key from the store' do
41
+ redis_be = mock store: mock
42
+ redis_be.store.should_receive(:del).with 'foo.bar'
43
+ Riddick::Backends::Redis.new(redis_be).delete_translation 'foo.bar'
44
+ end
45
+ end
46
+
47
+ describe Riddick::Backends::Redis::Value do
48
+ it 'should be a general key value value' do
49
+ v = Riddick::Backends::Redis::Value.new '"foo"'
50
+ v.should be_kind_of(Riddick::Backends::KeyValue::Value)
51
+ end
52
+
53
+ it 'should return decoded string' do
54
+ v = Riddick::Backends::Redis::Value.new MultiJson.encode('foo')
55
+ v.to_s.should == 'foo'
56
+
57
+ v = Riddick::Backends::Redis::Value.new MultiJson.encode(%w[foo bar baz])
58
+ v.to_s.should == '["foo", "bar", "baz"]'
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riddick::Backends::Simple do
4
+ describe 'creating a new backend' do
5
+ it 'should store i18n backend' do
6
+ i18n_be = mock
7
+ Riddick::Backends::Simple.new(i18n_be).i18n_backend.should == i18n_be
8
+ end
9
+ end
10
+
11
+ describe '#translations' do
12
+ it 'should return normalized translation from i18n backend' do
13
+ I18n.stub(:locale).and_return :en
14
+ i18n_be = mock translations: {en: {'foo' => {'bar' => 'baz'}}}
15
+ Riddick::Backends::Simple.new(i18n_be).translations.should == {'en.foo.bar' => 'baz'}
16
+ end
17
+ end
18
+
19
+ describe '#init_translations' do
20
+ it 'should init translations of i18n backend' do
21
+ i18n_be = mock
22
+ i18n_be.should_receive :init_translations
23
+ Riddick::Backends::Simple.new(i18n_be).init_translations
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riddick::Backends do
4
+ describe '#chain' do
5
+ context 'when not set via setter method' do
6
+ it 'should return I18n backend chain' do
7
+ Riddick::Backends.chain.should == I18n.backend
8
+ end
9
+ end
10
+
11
+ context 'when set via setter method' do
12
+ it 'should return the chain object' do
13
+ chain = mock
14
+ Riddick::Backends.chain = chain
15
+ Riddick::Backends.chain.should == chain
16
+ end
17
+ end
18
+ end
19
+
20
+ describe '#simple' do
21
+ let(:kv_be) { I18n::Backend::KeyValue.new({}) }
22
+ let(:s_be) { I18n::Backend::Simple.new }
23
+ let(:chain) { mock backends: [kv_be, s_be] }
24
+
25
+ before do
26
+ Riddick::Backends.chain = chain
27
+ end
28
+
29
+ context 'when no set via setter method' do
30
+ it 'should determine backend dynamically' do
31
+ Riddick::Backends.simple.should be_kind_of(Riddick::Backends::Simple)
32
+ Riddick::Backends.simple.i18n_backend.should == s_be
33
+ end
34
+ end
35
+
36
+ context 'when set via setter method' do
37
+ it 'should return the backend object' do
38
+ Riddick::Backends.simple = s_be
39
+ Riddick::Backends.simple.should == s_be
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#key_value' do
45
+ let(:kv_be) { I18n::Backend::KeyValue.new({}) }
46
+ let(:s_be) { I18n::Backend::Simple.new }
47
+ let(:chain) { mock backends: [kv_be, s_be] }
48
+
49
+ before do
50
+ Riddick::Backends.chain = chain
51
+ end
52
+
53
+ context 'when no set via setter method' do
54
+ it 'should determine backend dynamically' do
55
+ Riddick::Backends.key_value.should be_kind_of(Riddick::Backends::Redis)
56
+ Riddick::Backends.key_value.i18n_backend.should == kv_be
57
+ end
58
+ end
59
+
60
+ context 'when set via setter method' do
61
+ it 'should return the backend object' do
62
+ Riddick::Backends.key_value = kv_be
63
+ Riddick::Backends.key_value.should == kv_be
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#store_translation' do
69
+ it 'should store unescaped translation in chain with correctly determined path' do
70
+ chain = mock
71
+ Riddick::Backends.chain = chain
72
+ chain.should_receive(:store_translations).with 'en', {'foo.bar' => 'baz'}, {escape: false}
73
+ Riddick::Backends.store_translation 'en.foo.bar', 'baz'
74
+ end
75
+ end
76
+
77
+ describe '#delete_translation' do
78
+ it 'should delete translation from key value backend' do
79
+ kv_be = mock
80
+ Riddick::Backends.key_value = kv_be
81
+ kv_be.should_receive(:delete_translation).with 'foo.bar'
82
+ Riddick::Backends.delete_translation 'foo.bar'
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ describe '#riddick_normalize_i18n' do
5
+ it 'should return i18n-style hash' do
6
+ {
7
+ foo: {
8
+ bar: 'baz',
9
+ blub: 'bla',
10
+ }
11
+ }.riddick_normalize_i18n('en').should == {'en.foo.bar' => 'baz', 'en.foo.blub' => 'bla'}
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,133 @@
1
+ require 'capybara/rspec'
2
+ require 'rack/test'
3
+ require 'spec_helper'
4
+
5
+ set :environment, :test
6
+
7
+ describe 'Riddick::Server', type: :request do
8
+ include Rack::Test::Methods
9
+
10
+ def app
11
+ Riddick::Server.new
12
+ end
13
+
14
+ let(:s_be) { mock }
15
+ let(:kv_be) { mock }
16
+
17
+ before do
18
+ Riddick::Backends.simple = s_be
19
+ Riddick::Backends.key_value = kv_be
20
+
21
+ s_be.should_receive :init_translations # Assert translations are initialized on load
22
+
23
+ load 'lib/riddick/server.rb'
24
+
25
+ s_be.stub(:translations).and_return({
26
+ 'en.k1' => 'default-v1',
27
+ 'en.k2' => 'default-v2',
28
+ })
29
+ kv_be.stub(:translations).and_return({
30
+ 'en.k2' => Riddick::Backends::Redis::Value.new('"my-v2"'),
31
+ 'en.k3' => Riddick::Backends::Redis::Value.new('"my-v3"'),
32
+ })
33
+ end
34
+
35
+ describe 'GET /' do
36
+ it 'should render list of all translations overlaying default with my' do
37
+ get '/'
38
+ last_response.should be_ok
39
+ last_response.body.should have_selector("option[value='en.k1'][data-v='default-v1']")
40
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
41
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
42
+ end
43
+ end
44
+
45
+ describe 'GET /my' do
46
+ it 'should render list of my translations' do
47
+ get '/my'
48
+ last_response.should be_ok
49
+ last_response.body.should_not have_selector("option[data-v^='default-']")
50
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
51
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
52
+ end
53
+ end
54
+
55
+ describe 'GET /default' do
56
+ it 'should render list of default translations' do
57
+ get '/default'
58
+ last_response.should be_ok
59
+ last_response.body.should_not have_selector("option[data-v^='my-']")
60
+ last_response.body.should have_selector("option[value='en.k1'][data-v='default-v1']")
61
+ last_response.body.should have_selector("option[value='en.k2'][data-v='default-v2']")
62
+ end
63
+ end
64
+
65
+ describe 'POST /set' do
66
+ context 'with valid params' do
67
+ it 'should store translation and redirect to my translation' do
68
+ Riddick::Backends.should_receive(:store_translation).with 'en.k1', 'my-v1' do
69
+ kv_be.stub(:translations).and_return({
70
+ 'en.k1' => Riddick::Backends::Redis::Value.new('"my-v1"'),
71
+ 'en.k2' => Riddick::Backends::Redis::Value.new('"my-v2"'),
72
+ 'en.k3' => Riddick::Backends::Redis::Value.new('"my-v3"'),
73
+ })
74
+ end
75
+ post '/set', k: 'en.k1', v: 'my-v1'
76
+ follow_redirect!
77
+ last_response.should be_ok
78
+ last_response.body.should_not have_selector("option[data-v^='default-']")
79
+ last_response.body.should have_selector("option[value='en.k1'][data-v='my-v1']")
80
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
81
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
82
+ end
83
+ end
84
+
85
+ context 'with incorrect params' do
86
+ it 'should not try to store translation and render index' do
87
+ Riddick::Backends.should_not_receive :store_translation
88
+
89
+ post '/set', k: 'en.k1', v: ''
90
+ follow_redirect!
91
+ last_response.should be_ok
92
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
93
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
94
+
95
+ post '/set', k: '', v: 'my-v1'
96
+ follow_redirect!
97
+ last_response.should be_ok
98
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
99
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
100
+ end
101
+ end
102
+ end
103
+
104
+ describe 'GET /del' do
105
+ context 'with valid key' do
106
+ it 'should delete translation and redirect root' do
107
+ Riddick::Backends.should_receive(:delete_translation).with 'en.k2' do
108
+ kv_be.stub(:translations).and_return({
109
+ 'en.k3' => Riddick::Backends::Redis::Value.new('"my-v3"'),
110
+ })
111
+ end
112
+ get '/del', k: 'en.k2'
113
+ follow_redirect!
114
+ last_response.should be_ok
115
+ last_response.body.should have_selector("option[value='en.k1'][data-v='default-v1']")
116
+ last_response.body.should have_selector("option[value='en.k2'][data-v='default-v2']")
117
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
118
+ end
119
+ end
120
+
121
+ context 'with invalid key' do
122
+ it 'should delete translation and redirect root' do
123
+ Riddick::Backends.should_not_receive :delete_translation
124
+ get '/del', k: ''
125
+ follow_redirect!
126
+ last_response.should be_ok
127
+ last_response.body.should have_selector("option[value='en.k1'][data-v='default-v1']")
128
+ last_response.body.should have_selector("option[value='en.k2'][data-v='my-v2']")
129
+ last_response.body.should have_selector("option[value='en.k3'][data-v='my-v3']")
130
+ end
131
+ end
132
+ end
133
+ end