rediscover 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/rediscover ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib/')
4
+ require 'rediscover'
5
+
6
+ Rediscover::App.new.main_loop()
@@ -0,0 +1,57 @@
1
+ require 'logger'
2
+ require 'forwardable'
3
+ require 'rediscover/exception_handler'
4
+ require 'rediscover/icon'
5
+ require 'rediscover/frame/connect'
6
+ require 'rediscover/frame/main'
7
+ require 'rediscover/dialog/error'
8
+ require 'rediscover/dialog/confirm'
9
+
10
+ module Rediscover
11
+ class App < Wx::App
12
+
13
+ DEFAULTS = {
14
+ :host => 'localhost',
15
+ :port => 6379
16
+ }
17
+
18
+ attr_reader :logger, :host, :port, :redis
19
+
20
+ def on_init
21
+ @logger = Logger.new(STDOUT)
22
+ ExceptionHandler.set_logger(@logger)
23
+ @host = DEFAULTS[:host]
24
+ @port = DEFAULTS[:port]
25
+
26
+ display_connect
27
+ end
28
+
29
+ def display_connect
30
+ @connect_frame = Frame::Connect.new
31
+ end
32
+
33
+ def display_main
34
+ @main_frame = Frame::Main.new
35
+ end
36
+
37
+ def connect(host, port)
38
+ begin
39
+ @redis = Redis.new(:host => host, :port => port)
40
+ @redis.connect_to_server # connection errors will be rescued by Frame::Connect
41
+ @host, @port = host, port
42
+ @connect_frame.close
43
+ rescue => e
44
+ logger.error(e)
45
+ @conn_refused_dlg = Dialog::Error.new(@connect_frame,
46
+ "Can't connect to server.",
47
+ 'Unable to Connect')
48
+ @conn_refused_dlg.show_modal
49
+ return
50
+ end
51
+
52
+ @logger.info(@redis.to_s)
53
+ display_main
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,12 @@
1
+ module Rediscover
2
+ module Dialog
3
+ class Confirm < Wx::MessageDialog
4
+ include Wx
5
+
6
+ def initialize(window, message, caption)
7
+ super(window, message, caption, YES_NO|ICON_QUESTION)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Rediscover
2
+ module Dialog
3
+ class Error < Wx::MessageDialog
4
+ include Wx
5
+
6
+ def initialize(window, message, caption)
7
+ super(window, message, caption, OK|ICON_ERROR)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Rediscover
2
+ class ExceptionHandler
3
+
4
+ def self.set_logger(logger)
5
+ @@logger = logger
6
+ end
7
+
8
+ def self.modal(window, exception)
9
+ self.log(exception)
10
+ dlg = Rediscover::Dialog::Error.new(window,
11
+ 'An error occurred: ' + exception.to_s,
12
+ 'Error')
13
+ dlg.show_modal
14
+ end
15
+
16
+ def self.log(exception)
17
+ @@logger.error(exception)
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ module Rediscover
2
+ module Frame
3
+
4
+ class Connect < Wx::Frame
5
+ include Wx
6
+
7
+ def initialize
8
+ @app = get_app
9
+ super(nil, -1, 'Connect to Redis')
10
+
11
+ set_icon(Rediscover::Icon.new('server_connect'))
12
+
13
+ setup_panel
14
+ show
15
+ end
16
+
17
+ def setup_panel
18
+ @panel = Wx::Panel.new(self)
19
+ @host_label = StaticText.new(@panel, :label => 'Host')
20
+ @host_textbox = TextCtrl.new(@panel, :value => @app.host)
21
+ @port_label = StaticText.new(@panel, :label => 'Port')
22
+ @port_textbox = TextCtrl.new(@panel, :value => @app.port.to_s)
23
+ @connect_button = Button.new(@panel, :label => 'Connect')
24
+
25
+ evt_button @connect_button, :connect_button_evt
26
+
27
+ @panel_sizer = BoxSizer.new(VERTICAL)
28
+ @panel.set_sizer(@panel_sizer)
29
+ @panel_sizer.add(@host_label, 0, GROW|ALL, 2)
30
+ @panel_sizer.add(@host_textbox, 0, GROW|ALL, 2)
31
+ @panel_sizer.add(@port_label, 0, GROW|ALL, 2)
32
+ @panel_sizer.add(@port_textbox, 0, GROW|ALL, 2)
33
+ @panel_sizer.add(@connect_button, 0, GROW|ALL, 2)
34
+ end
35
+
36
+ def connect_button_evt
37
+ host = @host_textbox.get_value
38
+ port = @port_textbox.get_value.to_i
39
+ @app.connect(host, port)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,56 @@
1
+ module Rediscover
2
+ module Frame
3
+ class CreateKey < Wx::Frame
4
+ include Wx
5
+
6
+ def initialize(window)
7
+ @redis = get_app.redis
8
+ super(window, -1, 'Create a Key')
9
+
10
+ set_icon(Rediscover::Icon.new('key_add'))
11
+
12
+ setup_panel
13
+ show
14
+ end
15
+
16
+ def setup_panel
17
+ @panel = Wx::Panel.new(self)
18
+ @key_label = StaticText.new(@panel, :label => 'Key')
19
+ @key_textbox = TextCtrl.new(@panel)
20
+ @value_label = StaticText.new(@panel, :label => 'Value')
21
+ @value_textbox = TextCtrl.new(@panel)
22
+ @create_button = Button.new(@panel, :label => 'Create')
23
+
24
+ evt_button @create_button, :create_evt
25
+
26
+ @panel_sizer = BoxSizer.new(VERTICAL)
27
+ @panel.set_sizer(@panel_sizer)
28
+ @panel_sizer.add(@key_label, 0, GROW|ALL, 2)
29
+ @panel_sizer.add(@key_textbox, 0, GROW|ALL, 2)
30
+ @panel_sizer.add(@value_label, 0, GROW|ALL, 2)
31
+ @panel_sizer.add(@value_textbox, 0, GROW|ALL, 2)
32
+ @panel_sizer.add(@create_button, 0, GROW|ALL, 2)
33
+ end
34
+
35
+ def on_create(&block)
36
+ @on_create_block = block
37
+ end
38
+
39
+ def create_evt
40
+ key = @key_textbox.get_value
41
+ value = @value_textbox.get_value
42
+
43
+ begin
44
+ @redis[key] = value
45
+ rescue => e
46
+ ExceptionHandler.modal(self, e)
47
+ return
48
+ end
49
+
50
+ @on_create_block.call() if @on_create_block
51
+ close
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,59 @@
1
+ require 'rediscover/panel/server'
2
+ require 'rediscover/panel/browser'
3
+ require 'rediscover/panel/key_list'
4
+ require 'rediscover/key_viewer'
5
+ require 'rediscover/set_element_list'
6
+ require 'rediscover/sorted_set_element_list'
7
+ require 'rediscover/list_element_list'
8
+ require 'rediscover/panel/string_view'
9
+ require 'rediscover/panel/set_view'
10
+ require 'rediscover/panel/sorted_set_view'
11
+ require 'rediscover/panel/list_view'
12
+ require 'rediscover/frame/create_key'
13
+
14
+ module Rediscover
15
+ module Frame
16
+ class Main < Wx::Frame
17
+ include Wx
18
+
19
+ WINDOW_WIDTH = 600
20
+ WINDOW_HEIGHT = 400
21
+
22
+ def initialize
23
+ super(nil, -1, 'Rediscover', DEFAULT_POSITION, Size.new(WINDOW_WIDTH, WINDOW_HEIGHT))
24
+
25
+ @redis = get_app.redis
26
+ @logger = get_app.logger
27
+
28
+ set_icon(Rediscover::Icon.new('application'))
29
+
30
+ setup_status_bar
31
+ setup_notebook
32
+ show
33
+ end
34
+
35
+ def setup_notebook
36
+ @notebook = Notebook.new(self)
37
+
38
+ @server_page = Panel::Server.new(@notebook)
39
+ @browser_page = Panel::Browser.new(@notebook)
40
+ @browser_page.on_status_change { |status| update_status_bar(status) }
41
+
42
+ @notebook.add_page(@server_page, 'Server Info', false)
43
+ @notebook.add_page(@browser_page, 'Key Browser', true)
44
+ end
45
+
46
+ def setup_status_bar
47
+ @status_bar = create_status_bar(2)
48
+ @status_bar.set_status_widths([-3, -1]) # set fields to variable widths
49
+ update_status_bar
50
+ end
51
+
52
+ def update_status_bar(status = nil)
53
+ @status_bar.set_status_text(@redis.to_s, 0) # connection info in left field
54
+ @status_bar.set_status_text(status, 1) if status # key count in right field
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,12 @@
1
+ module Rediscover
2
+ class Icon < Wx::Icon
3
+
4
+ @@icon_dir = File.join( File.dirname(__FILE__), 'icons')
5
+
6
+ def initialize(icon_name)
7
+ icon_file = File.join(@@icon_dir, "#{icon_name}.png")
8
+ super(icon_file, Wx::BITMAP_TYPE_PNG)
9
+ end
10
+
11
+ end
12
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,117 @@
1
+ module Rediscover
2
+ class KeyListCtrl < Wx::ListCtrl
3
+ include Wx
4
+
5
+ COLS = %w(Key Value Type TTL)
6
+
7
+ def initialize(window)
8
+ @redis = get_app.redis
9
+ @logger = get_app.logger
10
+
11
+ super(window, :style => LC_REPORT|LC_VIRTUAL)
12
+
13
+ i = 0
14
+ COLS.each do |name|
15
+ insert_column(i += 1, name)
16
+ end
17
+ set_column_width(0, 200)
18
+ set_column_width(1, 200)
19
+
20
+ evt_list_item_right_click self, :list_item_right_click_evt
21
+ end
22
+
23
+ def size
24
+ @keys.size
25
+ end
26
+
27
+ def on_get_keys(&block)
28
+ @on_get_keys_block = block
29
+ end
30
+
31
+ def update
32
+ @keys = @on_get_keys_block.call()
33
+ @logger.debug("KeyListCtrl loaded #{size} keys")
34
+ delete_all_items
35
+ set_item_count(size)
36
+ do_on_status_change
37
+ end
38
+
39
+ def delete(selections)
40
+ selections.each do |index|
41
+ key = @keys[index]
42
+ @redis.delete(key)
43
+ end
44
+ update
45
+ end
46
+
47
+ def on_get_item_text(item, column)
48
+ text = case column
49
+ when COLS.index('Key') then @keys[item]
50
+ when COLS.index('Value') then get_item_value(item)
51
+ when COLS.index('Type') then get_item_type(item)
52
+ when COLS.index('TTL') then @redis.ttl(@keys[item]).to_s
53
+ end
54
+
55
+ return text || ''
56
+ end
57
+
58
+ def get_item_type(item)
59
+ @redis.type?(@keys[item])
60
+ end
61
+
62
+ def get_item_value(item)
63
+ case get_item_type(item)
64
+ when 'string' then return @redis[@keys[item]]
65
+ when 'list' then return "#{@redis.list_length(@keys[item])} element(s)"
66
+ when 'set' then return "#{@redis.set_count(@keys[item])} element(s)"
67
+ when 'zset' then return "#{@redis.zset_count(@keys[item])} element(s)"
68
+ end
69
+ end
70
+
71
+ def list_item_right_click_evt(event)
72
+ menu = get_ctx_menu_for_selections(get_selections)
73
+ popup_menu(menu, event.get_point) if menu
74
+ end
75
+
76
+ def get_ctx_menu_for_selections(selections)
77
+ return nil if selections.empty?
78
+ @ctx_menu = Menu.new
79
+
80
+ if selections.size == 1 && @redis.type?(@keys[*selections]) != 'none'
81
+ @ctx_edit_item = MenuItem.new(@ctx_menu, -1, 'Edit')
82
+ evt_menu(@ctx_edit_item) { do_on_edit(*selections) }
83
+ end
84
+
85
+ # delete menu item
86
+ @ctx_delete_item = MenuItem.new(@ctx_menu, -1, 'Delete')
87
+ evt_menu(@ctx_delete_item) do
88
+ if ID_YES == Dialog::Confirm.new(self, 'Really delete selected key(s)?', 'Really delete?').show_modal
89
+ delete(selections)
90
+ end
91
+ end
92
+
93
+ @ctx_menu.append_item(@ctx_edit_item) if @ctx_edit_item
94
+ @ctx_menu.append_item(@ctx_delete_item)
95
+ @ctx_menu
96
+ end
97
+
98
+ def on_edit(&block)
99
+ @on_edit_block = block
100
+ end
101
+
102
+ def do_on_edit(selection)
103
+ key = @keys[selection]
104
+ @on_edit_block.call(key, @redis.type?(key), selection)
105
+ end
106
+
107
+ def on_status_change(&block)
108
+ @on_status_change_block = block
109
+ do_on_status_change
110
+ end
111
+
112
+ def do_on_status_change
113
+ @on_status_change_block.call("#{size} keys") if @on_status_change_block
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,17 @@
1
+ module KeyViewer
2
+ def on_save(&block)
3
+ @on_save_block = block
4
+ end
5
+
6
+ def do_on_save
7
+ @on_save_block.call() if @on_save_block
8
+ end
9
+
10
+ def on_close(&block)
11
+ @on_close_block = block
12
+ end
13
+
14
+ def do_on_close
15
+ @on_close_block.call() if @on_close_block
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ module Rediscover
2
+ class ListElementList < Wx::ListCtrl
3
+ include Wx
4
+
5
+ def initialize(parent, key, elements)
6
+ @parent, @key = parent, key
7
+ @redis = get_app.redis
8
+ @logger = get_app.logger
9
+
10
+ super(parent, :style => LC_REPORT)
11
+
12
+ setup
13
+ set_elements(elements)
14
+ end
15
+
16
+ def setup
17
+ insert_column(0, 'Elements')
18
+ set_column_width(LIST_AUTOSIZE, -1)
19
+ end
20
+
21
+ def set_elements(elements)
22
+ delete_all_items
23
+ i = 0
24
+ elements.each { |element| insert_item(i, element); i += 1 }
25
+ @elements = elements
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ module Rediscover
2
+ module Panel
3
+ class Browser < Wx::SplitterWindow
4
+ include Wx
5
+
6
+ def initialize(parent)
7
+ @parent = parent
8
+ super(@parent, -1)
9
+
10
+ @redis = get_app.redis
11
+ @logger = get_app.logger
12
+
13
+ @key_list_panel = Panel::KeyList.new(self)
14
+ @key_list_panel.on_edit { |key, type, item| edit(key, type, item)}
15
+
16
+ init(@key_list_panel) # just show the key list initially
17
+ end
18
+
19
+ def edit(key, type, item)
20
+ unsplit(@view_panel) if @view_panel
21
+
22
+ @view_panel = get_view_panel(key, type)
23
+ @view_panel.on_save { @key_list_panel.refresh(item) }
24
+ @view_panel.on_close { unsplit(@view_panel) }
25
+
26
+ split_horizontally(@key_list_panel, @view_panel)
27
+ end
28
+
29
+ def get_view_panel(key, type)
30
+ case type
31
+ when 'string' then return Panel::StringView.new(self, key)
32
+ when 'set' then return Panel::SetView.new(self, key)
33
+ when 'zset' then return Panel::SortedSetView.new(self, key)
34
+ when 'list' then return Panel::ListView.new(self, key)
35
+ end
36
+ end
37
+
38
+ def on_status_change(&block)
39
+ @key_list_panel.on_status_change { |status| block.call(status) }
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,89 @@
1
+ require 'rediscover/key_list_ctrl'
2
+
3
+ module Rediscover
4
+ module Panel
5
+ class KeyList < Wx::Panel
6
+ include Wx
7
+ extend Forwardable
8
+
9
+ def_delegators :@key_list, :on_edit
10
+
11
+ def initialize(parent)
12
+ @parent = parent
13
+ super(@parent, -1, :style => SUNKEN_BORDER)
14
+
15
+ @redis = get_app.redis
16
+ @logger = get_app.logger
17
+ @key_pattern = '*'
18
+
19
+ setup_sizer
20
+ setup_tool_bar
21
+ setup_key_browser
22
+ setup_key_shortcuts
23
+ end
24
+
25
+ def setup_sizer
26
+ @sizer = BoxSizer.new(VERTICAL)
27
+ set_sizer(@sizer)
28
+ end
29
+
30
+ def setup_tool_bar
31
+ @tool_bar_sizer = BoxSizer.new(HORIZONTAL)
32
+ @sizer.add_item(@tool_bar_sizer)
33
+
34
+ @add_button = Button.new(self, ID_ADD)
35
+ evt_button(@add_button) do
36
+ create_key_frame = Rediscover::Frame::CreateKey.new(self)
37
+ create_key_frame.on_create { refresh }
38
+ end
39
+
40
+ @refresh_button = Button.new(self, ID_REFRESH)
41
+ evt_button @refresh_button, :refresh
42
+
43
+ # filter input and button
44
+ @filter_textbox = TextCtrl.new(self,
45
+ :style => TE_PROCESS_ENTER,
46
+ :size => Size.new(200, -1))
47
+ evt_text_enter @filter_textbox, :filter # filter when enter is pressed in the textbox
48
+ @filter_button = Button.new(self, :label => 'Filter')
49
+ evt_button @filter_button, :filter # filter when button is pressed
50
+
51
+ # add elements to tool bar
52
+ @tool_bar_sizer.add_item(@add_button, :flag => ALL, :border => 1)
53
+ @tool_bar_sizer.add_item(@refresh_button, :flag => ALL, :border => 1)
54
+ @tool_bar_sizer.add_item(@filter_textbox, :flag => ALL, :border => 1)
55
+ @tool_bar_sizer.add_item(@filter_button, :flag => ALL, :border => 1)
56
+ end
57
+
58
+ def setup_key_shortcuts
59
+ evt_key_up { |event| refresh if event.get_key_code == K_F5 }
60
+ end
61
+
62
+ def setup_key_browser
63
+ @key_list = KeyListCtrl.new(self)
64
+ @sizer.add(@key_list, 1, EXPAND)
65
+ @key_list.on_get_keys { @redis.keys(@key_pattern).sort }
66
+ @key_list.update
67
+ end
68
+
69
+ def refresh(item = nil)
70
+ if(item)
71
+ @key_list.refresh_item(item)
72
+ else
73
+ @key_list.update
74
+ end
75
+ end
76
+
77
+ def filter
78
+ @key_pattern = @filter_textbox.get_value.strip
79
+ @key_pattern = '*' if @key_pattern.nil? or @key_pattern == ''
80
+ refresh
81
+ end
82
+
83
+ def on_status_change(&block)
84
+ @key_list.on_status_change { |status| block.call(status) }
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,72 @@
1
+ module Rediscover
2
+ module Panel
3
+ class ListView < Wx::Panel
4
+ include Wx
5
+ include KeyViewer
6
+
7
+ def initialize(parent, key)
8
+ @parent, @key = parent, key
9
+ @redis = get_app.redis
10
+ @logger = get_app.logger
11
+
12
+ super(@parent, -1, :style => SUNKEN_BORDER)
13
+
14
+ setup
15
+ end
16
+
17
+ def setup
18
+ members = @redis.lrange(@key, 0, -1)
19
+
20
+ @sizer = BoxSizer.new(VERTICAL)
21
+ set_sizer(@sizer)
22
+
23
+ @key_label = StaticText.new(self, :label => "Key: #{@key}")
24
+
25
+ @element_list = ListElementList.new(self, @key, members)
26
+
27
+ @button_sizer = BoxSizer.new(HORIZONTAL)
28
+
29
+ @lpush_button = Button.new(self, :label => 'Left Push')
30
+ evt_button(@lpush_button) { push(:lpush) }
31
+
32
+ @rpush_button = Button.new(self, :label => 'Right Push')
33
+ evt_button(@rpush_button) { push(:rpush) }
34
+
35
+ @lpop_button = Button.new(self, :label => 'Left Pop')
36
+ evt_button(@lpop_button) { pop(:lpop) }
37
+
38
+ @rpop_button = Button.new(self, :label => 'Right Pop')
39
+ evt_button(@rpop_button) { pop(:rpop) }
40
+
41
+ @close_button = Button.new(self, :label => 'Close')
42
+ evt_button @close_button, :do_on_close
43
+
44
+ @sizer.add_item(@key_label, :flag => ALL, :border => 2)
45
+ @sizer.add_item(@element_list, :proportion => 1, :flag => EXPAND|ALL, :border => 2)
46
+ @sizer.add_item(@button_sizer)
47
+
48
+ @button_sizer.add_item(@lpush_button, :flag => ALL, :border => 2)
49
+ @button_sizer.add_item(@rpush_button, :flag => ALL, :border => 2)
50
+ @button_sizer.add_item(@lpop_button, :flag => ALL, :border => 2)
51
+ @button_sizer.add_item(@rpop_button, :flag => ALL, :border => 2)
52
+ @button_sizer.add_item(@close_button, :flag => ALL, :border => 2)
53
+ end
54
+
55
+ def pop(dir = :lpop)
56
+ @redis.send(dir, @key)
57
+ @element_list.set_elements(@redis.lrange(@key, 0, -1))
58
+ do_on_save
59
+ end
60
+
61
+ def push(dir = :lpush)
62
+ @add_dlg = TextEntryDialog.new(self, 'Enter a new element:', 'Add Element')
63
+ if @add_dlg.show_modal == ID_OK
64
+ @redis.send(dir, @key, @add_dlg.get_value)
65
+ @element_list.set_elements(@redis.lrange(@key, 0, -1))
66
+ do_on_save
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ module Rediscover
2
+ module Panel
3
+ class Server < Wx::Panel
4
+ include Wx
5
+
6
+ REFRESH_INTERVAL = 5000
7
+
8
+ def initialize(parent)
9
+ @parent = parent
10
+ super(@parent, -1)
11
+
12
+ @redis = get_app.redis
13
+ @logger = get_app.logger
14
+
15
+ setup_sizer
16
+ setup_server_info
17
+ end
18
+
19
+ def setup_sizer
20
+ @sizer = BoxSizer.new(VERTICAL)
21
+ set_sizer(@sizer)
22
+ end
23
+
24
+ def setup_server_info
25
+ @server_info_text = StaticText.new(self, :label => get_info)
26
+ @sizer.add_item(@server_info_text)
27
+ timer = Timer.new(self)
28
+ evt_timer(timer.id) { refresh }
29
+ timer.start(REFRESH_INTERVAL)
30
+ end
31
+
32
+ def get_info
33
+ @redis.info.map { |key, value| "#{key}: #{value}" }.sort.join("\n")
34
+ end
35
+
36
+ def refresh
37
+ @server_info_text.set_label(get_info)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ module Rediscover
2
+ module Panel
3
+ class SetView < Wx::Panel
4
+ include Wx
5
+ include KeyViewer
6
+
7
+ def initialize(parent, key)
8
+ @parent, @key = parent, key
9
+ @redis = get_app.redis
10
+ @logger = get_app.logger
11
+
12
+ super(@parent, -1, :style => SUNKEN_BORDER)
13
+
14
+ setup
15
+ end
16
+
17
+ def setup
18
+ members = @redis.smembers(@key)
19
+
20
+ @sizer = BoxSizer.new(VERTICAL)
21
+ set_sizer(@sizer)
22
+
23
+ @key_label = StaticText.new(self, :label => "Key: #{@key}")
24
+
25
+ @element_list = SetElementList.new(self, @key, members)
26
+ @element_list.on_save { do_on_save }
27
+
28
+ @button_sizer = BoxSizer.new(HORIZONTAL)
29
+
30
+ @add_button = Button.new(self, :label => 'Add Element')
31
+ evt_button @add_button, :add
32
+
33
+ @close_button = Button.new(self, :label => 'Close')
34
+ evt_button @close_button, :do_on_close
35
+
36
+ @sizer.add_item(@key_label, :flag => ALL, :border => 2)
37
+ @sizer.add_item(@element_list, :proportion => 1, :flag => EXPAND|ALL, :border => 2)
38
+ @sizer.add_item(@button_sizer)
39
+
40
+ @button_sizer.add_item(@add_button, :flag => ALL, :border => 2)
41
+ @button_sizer.add_item(@close_button, :flag => ALL, :border => 2)
42
+ end
43
+
44
+ def add
45
+ @add_dlg = TextEntryDialog.new(self, 'Enter a new element:', 'Add Element')
46
+ if @add_dlg.show_modal == ID_OK
47
+ @redis.sadd(@key, @add_dlg.get_value)
48
+ @element_list.set_elements(@redis.smembers(@key))
49
+ do_on_save
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ module Rediscover
2
+ module Panel
3
+ class SortedSetView < Wx::Panel
4
+ include Wx
5
+ include KeyViewer
6
+
7
+ def initialize(parent, key)
8
+ @parent, @key = parent, key
9
+ @redis = get_app.redis
10
+ @logger = get_app.logger
11
+
12
+ super(@parent, -1, :style => SUNKEN_BORDER)
13
+
14
+ setup
15
+ end
16
+
17
+ def setup
18
+ members = @redis.zrange(@key, 0, -1)
19
+
20
+ @sizer = BoxSizer.new(VERTICAL)
21
+ set_sizer(@sizer)
22
+
23
+ @key_label = StaticText.new(self, :label => "Key: #{@key}")
24
+
25
+ @element_list = SortedSetElementList.new(self, @key, members)
26
+ @element_list.on_save { do_on_save }
27
+
28
+ @button_sizer = BoxSizer.new(HORIZONTAL)
29
+
30
+ @add_button = Button.new(self, :label => 'Add Element')
31
+ evt_button @add_button, :add
32
+
33
+ @close_button = Button.new(self, :label => 'Close')
34
+ evt_button @close_button, :do_on_close
35
+
36
+ @sizer.add_item(@key_label, :flag => ALL, :border => 2)
37
+ @sizer.add_item(@element_list, :proportion => 1, :flag => EXPAND|ALL, :border => 2)
38
+ @sizer.add_item(@button_sizer)
39
+
40
+ @button_sizer.add_item(@add_button, :flag => ALL, :border => 2)
41
+ @button_sizer.add_item(@close_button, :flag => ALL, :border => 2)
42
+ end
43
+
44
+ def add
45
+ @add_dlg = TextEntryDialog.new(self, 'Enter a new element:', 'Add Element')
46
+ if @add_dlg.show_modal == ID_OK
47
+ @redis.zadd(@key, 0, @add_dlg.get_value) # TODO get a priority score
48
+ @element_list.set_elements(@redis.zrange(@key, 0, -1))
49
+ do_on_save
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,50 @@
1
+ module Rediscover
2
+ module Panel
3
+ class StringView < Wx::Panel
4
+ include Wx
5
+ include KeyViewer
6
+
7
+ def initialize(parent, key)
8
+ @parent = parent
9
+ super(@parent, -1, :style => SUNKEN_BORDER)
10
+
11
+ @key = key
12
+ @redis = get_app.redis
13
+
14
+ setup
15
+ end
16
+
17
+ def setup
18
+ value = @redis[@key]
19
+
20
+ @sizer = BoxSizer.new(VERTICAL)
21
+ set_sizer(@sizer)
22
+
23
+ @key_label = StaticText.new(self, :label => "Key: #{@key}")
24
+
25
+ @value_textbox = TextCtrl.new(self, :value => value, :style => TE_MULTILINE|TE_DONTWRAP)
26
+
27
+ @button_sizer = BoxSizer.new(HORIZONTAL)
28
+
29
+ @save_button = Button.new(self, :label => 'Save')
30
+ evt_button @save_button, :save
31
+
32
+ @close_button = Button.new(self, :label => 'Close')
33
+ evt_button @close_button, :do_on_close
34
+
35
+ @sizer.add_item(@key_label, :flag => ALL, :border => 2)
36
+ @sizer.add_item(@value_textbox, :proportion => 1, :flag => EXPAND|ALL, :border => 2)
37
+ @sizer.add_item(@button_sizer)
38
+
39
+ @button_sizer.add_item(@save_button, :flag => ALL, :border => 2)
40
+ @button_sizer.add_item(@close_button, :flag => ALL, :border => 2)
41
+ end
42
+
43
+ def save
44
+ @redis[@key] = @value_textbox.get_value
45
+ do_on_save
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ module Rediscover
2
+ class SetElementList < Wx::ListCtrl
3
+ include Wx
4
+
5
+ def initialize(parent, key, elements)
6
+ @parent, @key = parent, key
7
+ @redis = get_app.redis
8
+ @logger = get_app.logger
9
+
10
+ super(parent, :style => LC_REPORT)
11
+
12
+ setup
13
+ set_elements(elements)
14
+ end
15
+
16
+ def setup
17
+ insert_column(0, 'Elements')
18
+ set_column_width(LIST_AUTOSIZE, -1)
19
+ evt_list_item_right_click self, :list_item_right_click_evt
20
+ end
21
+
22
+ def set_elements(elements)
23
+ delete_all_items
24
+ i = 0
25
+ elements.each { |element| insert_item(i, element); i += 1 }
26
+ @elements = elements
27
+ end
28
+
29
+ def delete(selections)
30
+ delete_elements = selections.map { |index| @elements[index] }
31
+ delete_elements.each do |element|
32
+ @elements.delete(element)
33
+ @redis.srem(@key, element)
34
+ delete_item(find_item(0, element))
35
+ end
36
+ update
37
+ do_on_save
38
+ end
39
+
40
+ def list_item_right_click_evt(event)
41
+ menu = get_ctx_menu_for_selections(get_selections)
42
+ popup_menu(menu, event.get_point) if menu
43
+ end
44
+
45
+ def get_ctx_menu_for_selections(selections)
46
+ return nil if selections.empty?
47
+ @ctx_menu = Menu.new
48
+
49
+ # delete menu item
50
+ @ctx_delete_item = MenuItem.new(@ctx_menu, -1, 'Delete')
51
+ evt_menu(@ctx_delete_item) do
52
+ if ID_YES == Dialog::Confirm.new(self, 'Really delete selected element(s)?', 'Really delete?').show_modal
53
+ delete(selections)
54
+ end
55
+ end
56
+
57
+ @ctx_menu.append_item(@ctx_delete_item)
58
+ @ctx_menu
59
+ end
60
+
61
+ def on_save(&block)
62
+ @on_save_block = block
63
+ end
64
+
65
+ def do_on_save
66
+ @on_save_block.call() if @on_save_block
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,70 @@
1
+ module Rediscover
2
+ class SortedSetElementList < Wx::ListCtrl
3
+ include Wx
4
+
5
+ def initialize(parent, key, elements)
6
+ @parent, @key = parent, key
7
+ @redis = get_app.redis
8
+ @logger = get_app.logger
9
+
10
+ super(parent, :style => LC_REPORT)
11
+
12
+ setup
13
+ set_elements(elements)
14
+ end
15
+
16
+ def setup
17
+ insert_column(0, 'Elements')
18
+ set_column_width(LIST_AUTOSIZE, -1)
19
+ evt_list_item_right_click self, :list_item_right_click_evt
20
+ end
21
+
22
+ def set_elements(elements)
23
+ delete_all_items
24
+ i = 0
25
+ elements.each { |element| insert_item(i, element); i += 1 }
26
+ @elements = elements
27
+ end
28
+
29
+ def delete(selections)
30
+ delete_elements = selections.map { |index| @elements[index] }
31
+ delete_elements.each do |element|
32
+ @elements.delete(element)
33
+ @redis.zrem(@key, element)
34
+ delete_item(find_item(0, element))
35
+ end
36
+ update
37
+ do_on_save
38
+ end
39
+
40
+ def list_item_right_click_evt(event)
41
+ menu = get_ctx_menu_for_selections(get_selections)
42
+ popup_menu(menu, event.get_point) if menu
43
+ end
44
+
45
+ def get_ctx_menu_for_selections(selections)
46
+ return nil if selections.empty?
47
+ @ctx_menu = Menu.new
48
+
49
+ # delete menu item
50
+ @ctx_delete_item = MenuItem.new(@ctx_menu, -1, 'Delete')
51
+ evt_menu(@ctx_delete_item) do
52
+ if ID_YES == Dialog::Confirm.new(self, 'Really delete selected element(s)?', 'Really delete?').show_modal
53
+ delete(selections)
54
+ end
55
+ end
56
+
57
+ @ctx_menu.append_item(@ctx_delete_item)
58
+ @ctx_menu
59
+ end
60
+
61
+ def on_save(&block)
62
+ @on_save_block = block
63
+ end
64
+
65
+ def do_on_save
66
+ @on_save_block.call() if @on_save_block
67
+ end
68
+
69
+ end
70
+ end
data/lib/rediscover.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'wx'
3
+ require 'redis'
4
+ require 'rediscover/app'
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rediscover
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Kite
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-07 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: wxruby
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: redis
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.2
34
+ version:
35
+ description:
36
+ email:
37
+ executables:
38
+ - rediscover
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - lib/rediscover.rb
45
+ - lib/rediscover/key_list_ctrl.rb
46
+ - lib/rediscover/sorted_set_element_list.rb
47
+ - lib/rediscover/set_element_list.rb
48
+ - lib/rediscover/key_viewer.rb
49
+ - lib/rediscover/dialog/confirm.rb
50
+ - lib/rediscover/dialog/error.rb
51
+ - lib/rediscover/icon.rb
52
+ - lib/rediscover/panel/browser.rb
53
+ - lib/rediscover/panel/server.rb
54
+ - lib/rediscover/panel/list_view.rb
55
+ - lib/rediscover/panel/sorted_set_view.rb
56
+ - lib/rediscover/panel/string_view.rb
57
+ - lib/rediscover/panel/set_view.rb
58
+ - lib/rediscover/panel/key_list.rb
59
+ - lib/rediscover/frame/main.rb
60
+ - lib/rediscover/frame/create_key.rb
61
+ - lib/rediscover/frame/connect.rb
62
+ - lib/rediscover/exception_handler.rb
63
+ - lib/rediscover/list_element_list.rb
64
+ - lib/rediscover/icons/server_connect.png
65
+ - lib/rediscover/icons/refresh.png
66
+ - lib/rediscover/icons/key_add.png
67
+ - lib/rediscover/icons/application.png
68
+ - lib/rediscover/icons/add.png
69
+ - lib/rediscover/app.rb
70
+ - bin/rediscover
71
+ has_rdoc: true
72
+ homepage: http://github.com/chriskite/rediscover
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.5
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Redis GUI
99
+ test_files: []
100
+