aef-launchy-opensearch 1.2.1

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.
data/History.txt ADDED
@@ -0,0 +1,43 @@
1
+ === 1.2.1 / 2009-04-05
2
+
3
+ * 1 minor bugfix
4
+
5
+ * Loading path problem fixed
6
+
7
+ === 1.2.0 / 2009-04-05
8
+
9
+ * 1 major enhancement
10
+
11
+ * Namespaced into module Aef
12
+
13
+ * 5 minor enhancements
14
+
15
+ * Better metadata for gem
16
+ * Test refactoring
17
+ * Minor refactorings
18
+ * Improved documentation
19
+ * Added test for --version command
20
+ * Renamed gem and executable from launchy_opensearch to launchy-opensearch
21
+
22
+ * 1 minor bugfix
23
+
24
+ * Fixed some bugs related to Ruby 1.8.6
25
+
26
+ === 1.1.0 / 2009-03-08
27
+
28
+ * 1 major enhancements
29
+
30
+ * Better commandline outputs
31
+ * Now compatibile with ruby 1.9.1
32
+
33
+ * 3 minor enhancement
34
+
35
+ * Added a --version command to output version and licensing information
36
+ * Added automated tests
37
+ * Some more comments
38
+
39
+ === 1.0.0 / 2009-02-24
40
+
41
+ * 1 major enhancement
42
+
43
+ * Birthday!
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ COPYING.txt
5
+ Rakefile
6
+ bin/launchy-opensearch
7
+ lib/launchy_opensearch.rb
8
+ lib/launchy_opensearch/launchy_opensearch.rb
9
+ spec/launchy_opensearch_spec.rb
10
+ spec/fixtures/launchy.ini
11
+ spec/fixtures/discogs.xml
12
+ spec/fixtures/secure-wikipedia-english.xml
13
+ spec/fixtures/youtube.xml
data/README.rdoc ADDED
@@ -0,0 +1,164 @@
1
+ = LaunchyOpenSearch
2
+
3
+ * Project: https://rubyforge.org/projects/aef/
4
+ * RDoc: http://aef.rubyforge.org/launchy-opensearch/
5
+ * Github: http://github.com/aef/launchy-opensearch/
6
+
7
+ == DESCRIPTION:
8
+
9
+ LaunchyOpenSearch is a Ruby library and commandline tool that allows to parse
10
+ OpenSearch XML files and include them as search engines in the Weby plugin of
11
+ the keystroke app launcher Launchy by editing Launchy's ini config file.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Usable as library and commandline tool
16
+ * Tested and fully working on:
17
+ * Ubuntu Linux 8.10 i386_64 (Ruby 1.8.7 and 1.9.1p0)
18
+ * Debian GNU/Linux 4.0 i386 (Ruby 1.8.6)
19
+ * Windows XP i386 (Ruby 1.8.6)
20
+ * The commandline tool doesn't work with Ruby 1.9.x because the user-choices gem
21
+ is not yet updated. A patch is available here:
22
+ https://rubyforge.org/tracker/index.php?func=detail&aid=24307&group_id=4192&atid=16176
23
+
24
+ == SYNOPSIS:
25
+
26
+ === Commandline
27
+
28
+ Launchy should be closed while using OpenSearchLaunchy
29
+
30
+ launchy-opensearch youtube.xml
31
+
32
+ === Library
33
+
34
+ Notice that the library is written with an underscore instead of the dash used
35
+ in the gem's and commandline tool's name
36
+
37
+ require 'launchy_opensearch'
38
+
39
+ Determine launchy ini path
40
+
41
+ config_path = Aef::LaunchyOpenSearch.launchy_config_path
42
+
43
+ Parse an OpenSearch engine into a variable
44
+
45
+ new_engine = Aef::LaunchyOpenSearch.parse_opensearch_file('youtube.xml')
46
+
47
+ Read the launchy ini file into a variable
48
+
49
+ config = Aef::LaunchyOpenSearch.read_config_hash(config_path)
50
+
51
+ Extract hash with current search engines
52
+
53
+ current_engines = Aef::LaunchyOpenSearch.extract_config_hash(config)
54
+
55
+ Add new engine to the engines hash
56
+
57
+ new_engines = current_engines + new_engine
58
+
59
+ Patch the engines hash into the config hash
60
+
61
+ Aef::LaunchyOpenSearch.patch_config_hash(config, new_engines)
62
+
63
+ Write the config hash as ini back to the disk
64
+
65
+ Aef::LaunchyOpenSearch.write_config_hash(config, config_path)
66
+
67
+ == REQUIREMENTS:
68
+
69
+ * rubygems
70
+ * hpricot
71
+ * facets
72
+ * sys-uname
73
+
74
+ === Additional for commandline
75
+ * user-choices
76
+
77
+ === Additional for automated testing
78
+ * rspec
79
+
80
+ == INSTALL:
81
+
82
+ === Normal
83
+
84
+ gem install launchy-opensearch
85
+
86
+ Additionally for the commandline tool:
87
+
88
+ gem install user-choices
89
+
90
+ === High security (recommended)
91
+
92
+ There is a high security installation option available through rubygems. It is
93
+ highly recommended over the normal installation, although it may be a bit less
94
+ comfortable. To use the installation method, you will need my public key, which
95
+ I use for cryptographic signatures on all my gems. You can find the public key
96
+ and more detailed verification information in the aef-certificates section of my
97
+ rubyforge project[https://rubyforge.org/frs/?group_id=7890&release_id=31749]
98
+
99
+ Add the key to your rubygems' trusted certificates by the following command:
100
+
101
+ gem cert --add aef.pem
102
+
103
+ Now you can install the gem while automatically verifying it's signature by the
104
+ following command:
105
+
106
+ gem install launchy-opensearch --ignore-dependencies -P HighSecurity
107
+
108
+ Please notice that you will need other keys for dependent libraries, so you may
109
+ have to install dependencies manually.
110
+
111
+ === Automated testing
112
+
113
+ You can test this package through rspec on your system. First find the path
114
+ where the gem was installed to:
115
+
116
+ gem which launchy-opensearch
117
+
118
+ Go into the root directory of the installed gem and run the following command
119
+ to start the test runner:
120
+
121
+ rake spec
122
+
123
+ On Windows systems you have to run the following instead:
124
+
125
+ spec spec/**/*_spec.rb
126
+
127
+ If something goes wrong you should be noticed through failing examples.
128
+
129
+ == DEVELOPMENT:
130
+
131
+ This software is developed in the source code management system git hosted
132
+ at github.com. You can download the most recent sourcecode through the following
133
+ command:
134
+
135
+ git clone git://github.com/aef/launchy-opensearch.git
136
+
137
+ Help on making this software better is always very appreciated. If you want your
138
+ changes to be included in the official release, please send me a patch through
139
+ the project's tracker[https://rubyforge.org/tracker/?group_id=7890] at
140
+ rubyforge.org. You can generate a patch-file by the following command:
141
+
142
+ git diff > patch.diff
143
+
144
+ Please make sure to write tests for your changes and notice that I can't promise
145
+ to include your changes before reviewing them.
146
+
147
+ == LICENSE:
148
+
149
+ Copyright 2009 Alexander E. Fischer <aef@raxys.net>
150
+
151
+ This file is part of LaunchyOpenSearch.
152
+
153
+ LaunchyOpenSearch is free software: you can redistribute it and/or modify
154
+ it under the terms of the GNU General Public License as published by
155
+ the Free Software Foundation, either version 3 of the License, or
156
+ (at your option) any later version.
157
+
158
+ This program is distributed in the hope that it will be useful,
159
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
160
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
161
+ GNU General Public License for more details.
162
+
163
+ You should have received a copy of the GNU General Public License
164
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/launchy_opensearch.rb'
6
+
7
+ Hoe.new('launchy-opensearch', Aef::LaunchyOpenSearch::VERSION) do |p|
8
+ p.rubyforge_name = 'aef'
9
+ p.developer('Alexander E. Fischer', 'aef@raxys.net')
10
+ p.extra_deps = %w{facets hpricot sys-uname}
11
+ p.extra_dev_deps = %w{user-choices}
12
+ p.url = 'https://rubyforge.org/projects/aef/'
13
+ p.readme_file = 'README.rdoc'
14
+ p.extra_rdoc_files = %w{README.rdoc}
15
+ p.spec_extras = {
16
+ :rdoc_options => ['--main', 'README.rdoc', '--inline-source', '--line-numbers', '--title', 'LaunchyOpenSearch']
17
+ }
18
+ end
19
+
20
+ # vim: syntax=Ruby
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
4
+ #
5
+ # This file is part of LaunchyOpenSearch.
6
+ #
7
+ # LaunchyOpenSearch is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ # TODO: If user-choices patch gets accepted, use :one_way => true for --version
21
+
22
+ # If library is not locally accessible, use gem to include it.
23
+ begin
24
+ require 'lib/launchy_opensearch'
25
+ rescue LoadError
26
+ require 'rubygems'
27
+ require 'launchy_opensearch'
28
+ end
29
+
30
+ # User friendly message if user-choices is not available
31
+ begin
32
+ require 'user-choices'
33
+ rescue LoadError
34
+ warn "This command needs the user-choices gem to be installed.\n\nSolution: gem install user-choices"; exit false
35
+ end
36
+
37
+ class Aef::LaunchyOpenSearch::Application < UserChoices::Command
38
+ include UserChoices
39
+
40
+ MODES = %w{append replace}
41
+
42
+ # Prepare configuration sources
43
+ def add_sources(builder)
44
+ builder.add_source(
45
+ CommandLineSource, :usage,
46
+ "Usage: #$PROGRAM_NAME [options] opensearch-files\n\n",
47
+ "Import OpenSearch XML files into the Weby plugin of the keystroke application launcher Launchy\n"
48
+ )
49
+ end
50
+
51
+ # Define configuration options
52
+ def add_choices(builder)
53
+ builder.add_choice(:config_path, :default => Aef::LaunchyOpenSearch.launchy_config_path) do |cli|
54
+ cli.uses_option('-c', '--config FILE',
55
+ 'Launchy ini file to modify. Uses the current user\'s config file by default.')
56
+ end
57
+
58
+ builder.add_choice(:mode, :default => MODES.first, :type => MODES ) do |cli|
59
+ cli.uses_option('-m', '--mode MODE',
60
+ "Insert mode. Possible settings: #{MODES.join(', ')}. Default is #{MODES.first}.")
61
+ end
62
+
63
+ builder.add_choice(:version, :default => false, :type => :boolean) do |cli|
64
+ cli.uses_switch('-v', '--version', 'Display version and licensing information')
65
+ end
66
+
67
+ builder.add_choice(:filenames) {|cli| cli.uses_arglist }
68
+ end
69
+
70
+ # Manual option post processing
71
+ def postprocess_user_choices
72
+ version if @user_choices[:version]
73
+ end
74
+
75
+ # Version and licensing information output
76
+ def version
77
+ name = 'LaunchyOpenSearch'
78
+ puts "#{name} #{Aef::LaunchyOpenSearch::VERSION}"
79
+ puts
80
+ puts 'Project: https://rubyforge.org/projects/aef/'
81
+ puts "RDoc: http://aef.rubyforge.org/launchy-opensearch/"
82
+ puts "Github: http://github.com/aef/launchy-opensearch/"
83
+ puts
84
+ puts 'Copyright 2009 Alexander E. Fischer <aef@raxys.net>'
85
+ # Read and print licensing information from the top of this file
86
+ if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new('1.8.6')
87
+ puts File.read(__FILE__).map{|line| line[2..-1]}[5..17]
88
+ else
89
+ puts File.read(__FILE__).lines.map{|line| line[2..-1]}[5..17]
90
+ end
91
+ exit
92
+ end
93
+
94
+ # Main program
95
+ def execute
96
+ if @user_choices[:filenames].empty?
97
+ warn 'No OpenSearch files specified'; exit false
98
+ end
99
+
100
+ @user_choices[:filenames].each do |filename|
101
+ warn "Ignoring #{filename}. Not readable or missing." unless File.readable?(filename)
102
+ end
103
+
104
+ new_engines = Aef::LaunchyOpenSearch.parse_opensearch_files(@user_choices[:filenames])
105
+ count = new_engines.size
106
+ config = Aef::LaunchyOpenSearch.read_config_hash(@user_choices[:config_path])
107
+
108
+ if @user_choices[:mode] == 'append'
109
+ current_engines = Aef::LaunchyOpenSearch.extract_config_hash(config)
110
+ new_engines = current_engines + new_engines
111
+ end
112
+
113
+ Aef::LaunchyOpenSearch.patch_config_hash(config, new_engines)
114
+ Aef::LaunchyOpenSearch.write_config_hash(config, @user_choices[:config_path])
115
+
116
+ puts "#{count} search engines installed."
117
+ end
118
+ end
119
+
120
+ S4tUtils.with_pleasant_exceptions {Aef::LaunchyOpenSearch::Application.new.execute}
@@ -0,0 +1,30 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of LaunchyOpenSearch.
4
+ #
5
+ # LaunchyOpenSearch is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Namespace for projects of Alexander E. Fischer <aef@raxys.net>
19
+ #
20
+ # If you want to be able to simply type Example instead of Aef::Example to
21
+ # address classes in this namespace simply write the following before using the
22
+ # classes:
23
+ #
24
+ # include Aef
25
+ module Aef
26
+
27
+ end
28
+
29
+ libdir = File.dirname(__FILE__)
30
+ require File.join(libdir, 'launchy_opensearch/launchy_opensearch')
@@ -0,0 +1,167 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of LaunchyOpenSearch.
4
+ #
5
+ # LaunchyOpenSearch is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'tempfile'
19
+ require 'uri'
20
+
21
+ require 'rubygems'
22
+ require 'hpricot'
23
+ require 'facets/ini'
24
+ require 'sys/uname'
25
+
26
+ # Offers static methods for all steps in parsing usefull information out of the
27
+ # OpenSearch XML format and modifying the configuration of Launchy's Weby plugin
28
+ module Aef::LaunchyOpenSearch
29
+
30
+ VERSION = '1.2.1'
31
+
32
+ # Determines the location of Launchy's configuration Ini file on different
33
+ # platforms
34
+ def self.launchy_config_path
35
+ if Sys::Uname.sysname.downcase.include?("windows")
36
+ File.join(ENV['APPDATA'], 'Launchy', 'Launchy.ini')
37
+ else
38
+ File.join(ENV['HOME'], '.launchy', 'launchy.ini')
39
+ end
40
+ end
41
+
42
+ # Parses an OpenSearch XML document
43
+ #
44
+ # Returns a Hash with the keys :name, :base, :query and :default
45
+ def self.parse_opensearch(content)
46
+ opensearch = Hpricot.XML(content)
47
+
48
+ uri = URI.parse(opensearch.at('os:Url').get_attribute('template').gsub(/\{searchTerms\}/, ':PLACEHOLDER'))
49
+
50
+ {
51
+ :name => opensearch.at('os:ShortName').inner_html,
52
+ :base => "#{uri.scheme}://#{uri.host}/",
53
+ :query => "\"#{uri.path[1..-1]}?#{uri.query}\"".gsub(/:PLACEHOLDER/, '%s'),
54
+ :default => 'false'
55
+ }
56
+ end
57
+
58
+ # Reads and parses a single OpenSearch file from the filesystem.
59
+ #
60
+ # Returns a Hash with the keys :name, :base, :query and :default
61
+ def self.parse_opensearch_file(file)
62
+ if file.is_a?(String)
63
+ content = File.read(file)
64
+ elsif file.respond_to?(:read)
65
+ content = file.read
66
+ else
67
+ raise "Expected file path as string or an object responding to read. Got #{file.class.name}"
68
+ end
69
+
70
+ parse_opensearch(content)
71
+ end
72
+
73
+ # Reads multiple OpenSearch files from filesystem
74
+ #
75
+ # Returns an Array of Hashes with the keys :name, :base, :query and :default
76
+ def self.parse_opensearch_files(file_list)
77
+ engines = []
78
+ file_list.each do |file|
79
+ if File.readable?(file)
80
+ engines << parse_opensearch_file(file)
81
+ end
82
+ end
83
+ engines
84
+ end
85
+
86
+ # Reads an Ini file from filesystem into a launchy config hash.
87
+ def self.read_config_hash(path)
88
+ # Ini class doesn't like empty lines and can only read from files.
89
+ original = File.read(path)
90
+
91
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9')
92
+ cleaned = original.lines.map{|line| line.chomp.squeeze(' ')}.reject{|line| line == ''}.join("\n")
93
+ else
94
+ cleaned = original.map{|line| line.chomp.squeeze(' ')}.reject{|line| line == ''}.join("\n")
95
+ end
96
+
97
+ temp_file = Tempfile.open('launchy')
98
+ temp_file.write(cleaned)
99
+ temp_file.close
100
+
101
+ config = Ini.read_from_file(temp_file.path)
102
+
103
+ temp_file.unlink
104
+
105
+ config
106
+ end
107
+
108
+ # Reads relevant parts out of the weby section of a launchy config hash.
109
+ #
110
+ # Returns an Array of Hashes with the keys :name, :base, :query and :default
111
+ def self.extract_config_hash(config_hash)
112
+ engines = {}
113
+ config_hash['weby'].each do |entry, value|
114
+ entry.match(/^sites\\([0-9]{1,2})\\(.*)$/)
115
+ if $1 and $2
116
+ engines[$1.to_i] ||= {}
117
+ engines[$1.to_i][$2.to_sym] = value
118
+ end
119
+ end
120
+
121
+ engines_array = []
122
+ engines.sort.each do |key, content|
123
+ engines_array << content
124
+ end
125
+ engines_array
126
+ end
127
+
128
+ # Replaces the site entries of the Weby section of a launchy config hash with
129
+ # an engines array as returned by extract_config_hash
130
+ #
131
+ # Attention: This method modifies the config hash given as argument. It is
132
+ # returned as result only for convenience.
133
+ def self.patch_config_hash(config_hash, engines)
134
+ new_section = {}
135
+ config_hash['weby'].each do |entry, value|
136
+ unless entry.match(/^sites\\/)
137
+ new_section[entry] = value
138
+ end
139
+ end
140
+ engines.each_with_index do |settings, i|
141
+ settings.each {|key, value|
142
+ new_section["sites\\#{i + 1}\\#{key}"] = value
143
+ }
144
+ end
145
+ new_section['sites\\size'] = engines.size.to_s
146
+ config_hash['weby'] = new_section
147
+ config_hash
148
+ end
149
+
150
+ # Writes a launchy config hash back to filesystem in INI format
151
+ def self.write_config_hash(config_hash, path)
152
+ if File.exists?(path) and File.readable?(path) and File.file?(path)
153
+ original = File.read(path)
154
+
155
+ File.open("#{path}.bak", 'w') do |f|
156
+ f.write(original)
157
+ end
158
+ end
159
+
160
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9')
161
+ # Facets ini parser doesn't seems to use the .lines enumerator yet
162
+ Ini.write_to_file(path, config_hash)
163
+ else
164
+ Ini.write_to_file(path, config_hash, "Written by LaunchyOpenSearch #{Time.now}\n")
165
+ end
166
+ end
167
+ end