radiant-ray-extension 3.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/LICENSE +19 -0
  2. data/README.markdown +30 -0
  3. data/Rakefile +26 -0
  4. data/bin/ray +5 -0
  5. data/doc/Extension.html +1189 -0
  6. data/doc/Ray.html +175 -0
  7. data/doc/Ray/CLI.html +585 -0
  8. data/doc/Ray/Cache.html +709 -0
  9. data/doc/Ray/Gem.html +760 -0
  10. data/doc/Ray/Git.html +278 -0
  11. data/doc/Ray/GitHub.html +553 -0
  12. data/doc/Ray/RubyGems.html +501 -0
  13. data/doc/Ray/Zip.html +300 -0
  14. data/doc/Search.html +433 -0
  15. data/doc/String.html +242 -0
  16. data/doc/_index.html +84 -0
  17. data/doc/class_list.html +47 -0
  18. data/doc/css/common.css +1 -0
  19. data/doc/css/full_list.css +55 -0
  20. data/doc/css/style.css +322 -0
  21. data/doc/file.LICENSE.html +85 -0
  22. data/doc/file.README.html +97 -0
  23. data/doc/file_list.html +46 -0
  24. data/doc/frames.html +13 -0
  25. data/doc/index.html +84 -0
  26. data/doc/js/app.js +205 -0
  27. data/doc/js/full_list.js +167 -0
  28. data/doc/js/jquery.js +16 -0
  29. data/doc/method_list.html +46 -0
  30. data/doc/top-level-namespace.html +105 -0
  31. data/lib/ray.rb +8 -0
  32. data/lib/ray/cli.rb +271 -0
  33. data/lib/ray/constants.rb +17 -0
  34. data/lib/ray/extension.rb +116 -0
  35. data/lib/ray/extension/gem.rb +96 -0
  36. data/lib/ray/extension/git.rb +30 -0
  37. data/lib/ray/extension/zip.rb +44 -0
  38. data/lib/ray/search.rb +62 -0
  39. data/lib/ray/search/cache.rb +61 -0
  40. data/lib/ray/search/github.rb +40 -0
  41. data/lib/ray/search/rubygems.rb +36 -0
  42. data/lib/ray/string.rb +18 -0
  43. data/ray.gemspec +31 -0
  44. data/spec/fixtures/Gemfile +4 -0
  45. data/spec/fixtures/cache_single.yml +8 -0
  46. data/spec/fixtures/cassettes/github_v2_api_no_matches.yml +38 -0
  47. data/spec/fixtures/cassettes/github_v2_api_search_no_matches.yml +38 -0
  48. data/spec/fixtures/cassettes/github_v2_api_search_reorder_children.yml +75 -0
  49. data/spec/fixtures/cassettes/github_v2_api_search_single.yml +74 -0
  50. data/spec/fixtures/cassettes/github_v3_api_owner_name.yml +75 -0
  51. data/spec/fixtures/cassettes/rubygems_v1_api_gem_info.yml +36 -0
  52. data/spec/fixtures/cassettes/rubygems_v1_api_no_matches.yml +34 -0
  53. data/spec/fixtures/cassettes/rubygems_v1_api_search_no_matches.yml +34 -0
  54. data/spec/fixtures/cassettes/rubygems_v1_api_search_reorder.yml +36 -0
  55. data/spec/fixtures/cassettes/rubygems_v1_api_search_reorder_children.yml +36 -0
  56. data/spec/fixtures/cassettes/rubygems_v1_api_search_single.yml +41 -0
  57. data/spec/fixtures/cassettes/zip_file.yml +101 -0
  58. data/spec/fixtures/dummy.zip +0 -0
  59. data/spec/fixtures/dummy/README +1 -0
  60. data/spec/fixtures/dummy/Rakefile +109 -0
  61. data/spec/fixtures/dummy/config/initializers/radiant_config.rb +3 -0
  62. data/spec/fixtures/dummy/config/locales/en.yml +3 -0
  63. data/spec/fixtures/dummy/config/routes.rb +5 -0
  64. data/spec/fixtures/dummy/dummy_extension.rb +21 -0
  65. data/spec/fixtures/dummy/lib/radiant-dummy-extension.rb +8 -0
  66. data/spec/fixtures/dummy/lib/tasks/dummy_extension_tasks.rake +47 -0
  67. data/spec/fixtures/dummy/public/stylesheets/extensions/dummy/dummy.css +0 -0
  68. data/spec/fixtures/dummy/radiant-dummy-extension.gemspec +29 -0
  69. data/spec/ray/cli_spec.rb +56 -0
  70. data/spec/ray/extension/gem_spec.rb +214 -0
  71. data/spec/ray/extension/git_spec.rb +216 -0
  72. data/spec/ray/extension/zip_spec.rb +239 -0
  73. data/spec/ray/search/cache_spec.rb +74 -0
  74. data/spec/ray/search/github_spec.rb +137 -0
  75. data/spec/ray/search/rubygems_spec.rb +127 -0
  76. data/spec/ray/string_spec.rb +30 -0
  77. data/spec/spec_helper.rb +27 -0
  78. metadata +205 -0
@@ -0,0 +1,17 @@
1
+ # Friendly extension management for Radiant CMS
2
+ module Ray
3
+
4
+ VERSION = "3.0.0.alpha"
5
+
6
+ RAY = File.expand_path "~/.ray"
7
+ CACHE = "#{RAY}/cache.yml"
8
+
9
+ ROOT = File.expand_path Dir.pwd
10
+ GEMFILE = "#{ROOT}/Gemfile"
11
+ EXT_DIR = "#{ROOT}/vendor/extensions"
12
+ TMP_DIR = "#{ROOT}/tmp/ray"
13
+ RG_V1_API = "http://rubygems.org/api/v1"
14
+ GH_V2_API = "http://github.com/api/v2/json"
15
+ GH_V3_API = "https://api.github.com"
16
+
17
+ end
@@ -0,0 +1,116 @@
1
+ require "fileutils"
2
+ require "open-uri"
3
+ require "rake"
4
+ require "ray/string"
5
+
6
+ module Extension
7
+
8
+ attr_accessor :author,
9
+ :description,
10
+ :homepage,
11
+ :name,
12
+ :uri,
13
+ :version
14
+
15
+ def initialize options = {}
16
+ @author = options[:author]
17
+ @description = options[:description]
18
+ @homepage = options[:homepage]
19
+ @name = options[:name].to_s.to_extension_name
20
+ @uri = options[:uri]
21
+ @version = options[:version]
22
+ end
23
+
24
+ def disable
25
+ unless File.exist? "#{Ray::EXT_DIR}/#{@name}"
26
+ raise "The #{@name} extension is not installed"
27
+ end
28
+
29
+ FileUtils.mkdir_p "#{Ray::EXT_DIR}/.disabled"
30
+ FileUtils.mv "#{Ray::EXT_DIR}/#{@name}", "#{Ray::EXT_DIR}/.disabled/#{@name}"
31
+ end
32
+
33
+ def enable
34
+ unless File.exist? "#{Ray::EXT_DIR}/.disabled/#{@name}"
35
+ raise "The #{@name} extension is not disabled"
36
+ end
37
+
38
+ FileUtils.mv "#{Ray::EXT_DIR}/.disabled/#{@name}", "#{Ray::EXT_DIR}/#{@name}"
39
+ end
40
+
41
+ def uninstall
42
+ unless File.exist? "#{Ray::EXT_DIR}/#{@name}"
43
+ raise "The #{@name} extension is not installed"
44
+ end
45
+
46
+ run_tasks({
47
+ :migrate => "VERSION=0",
48
+ :update => :psa
49
+ })
50
+ FileUtils.rm_rf "#{Ray::EXT_DIR}/#{@name}"
51
+ end
52
+
53
+ def download
54
+ raise "The extension name is required" unless @name
55
+ raise "The extension URI is required" unless @uri
56
+
57
+ puts "#{@name} => Downloading..."
58
+ FileUtils.mkdir_p Ray::TMP_DIR
59
+ tmpfile = open(@uri).path
60
+ FileUtils.cp tmpfile, "#{Ray::TMP_DIR}/#{@uri.split('/').last}"
61
+ end
62
+
63
+ def vendor
64
+ puts "#{@name} => Vendoring..."
65
+ directory = Dir.glob("#{Ray::TMP_DIR}/*").first
66
+ FileUtils.mv directory, "#{Ray::EXT_DIR}/#{@name}"
67
+ end
68
+
69
+ def run_tasks options = { :migrate => "", :update => "" }
70
+ tasks = load_tasks
71
+ tasks.each do |task|
72
+ case task
73
+ when "radiant:extensions:#{@name}:install"
74
+ run_task "install"
75
+ break
76
+ when "radiant:extensions:#{@name}:migrate"
77
+ run_task "migrate", options[:migrate]
78
+ when "radiant:extensions:#{@name}:update"
79
+ run_task "update", options[:update]
80
+ end
81
+ end
82
+ end
83
+
84
+ def run_task task, options = {}
85
+ puts "#{@name} => Running #{task} task..."
86
+ if task == "update" and options == :psa
87
+ public_service_announcement
88
+ else
89
+ `rake radiant:extensions:#{@name}:#{task} #{options}`
90
+ end
91
+ end
92
+
93
+ def load_tasks
94
+ puts "#{@name} => Loading tasks..."
95
+ rake_file = "#{Ray::ROOT}/vendor/extensions/#{@name}/lib/tasks/#{@name}_extension_tasks.rake"
96
+ load rake_file if File.exist? rake_file
97
+ Rake.application.tasks.map(&:name)
98
+ end
99
+
100
+ def cleanup
101
+ puts "#{@name} => Removing temporary files..."
102
+ FileUtils.rm_rf Ray::TMP_DIR
103
+ end
104
+
105
+ def public_service_announcement path = nil
106
+ path ||= "#{Ray::EXT_DIR}/#{@name}"
107
+ Dir.glob("#{path}/public/**/*.*").each do |f|
108
+ FileUtils.rm_rf File.expand_path(f.sub! /#{path}\//, "")
109
+ end
110
+ end
111
+
112
+ def name= name
113
+ @name = name.to_extension_name
114
+ end
115
+
116
+ end
@@ -0,0 +1,96 @@
1
+ require "multi_json"
2
+ require "ray/extension"
3
+
4
+ module Ray
5
+
6
+ class Gem
7
+
8
+ include Extension
9
+
10
+ def initialize options = {}
11
+ @author = options[:author]
12
+ @description = options[:description]
13
+ @homepage = options[:homepage]
14
+ @name = options[:name].to_s.to_extension_name
15
+ @uri = options[:uri]
16
+ @version = options[:version] || version
17
+ end
18
+
19
+ def install
20
+ unless @name
21
+ raise "The extension name is required"
22
+ end
23
+
24
+ add_gem
25
+ bundle
26
+ copy_tasks
27
+ run_tasks
28
+ end
29
+ alias enable install
30
+
31
+ def add_gem
32
+ puts "#{@name} => Adding to Gemfile..."
33
+ File.open GEMFILE, "a" do |gemfile|
34
+ gemfile.puts "gem \"radiant-#{@name}-extension\", \"~> #{@version}\""
35
+ end
36
+ end
37
+
38
+ def version
39
+ return 0 unless @name
40
+ uri = "#{RG_V1_API}/gems/radiant-#{@name}-extension.json"
41
+ response = open(uri).read
42
+ MultiJson.decode(response)["version"]
43
+ end
44
+
45
+ def bundle
46
+ puts "#{@name} => Bundling..."
47
+ FileUtils.rm "#{Ray::GEMFILE}.lock"
48
+ `bundle update`
49
+ end
50
+
51
+ def copy_tasks
52
+ puts "#{@name} => Copying tasks..."
53
+ path = `bundle show radiant-#{@name}-extension`.chomp
54
+ tasks = "#{path}/lib/tasks/#{@name}_extension_tasks.rake"
55
+ if File.exist? tasks
56
+ FileUtils.cp tasks, "#{Ray::ROOT}/lib/tasks/"
57
+ end
58
+ end
59
+
60
+ def load_tasks
61
+ puts "#{@name} => Loading tasks..."
62
+ rake_file = "#{Ray::ROOT}/lib/tasks/#{@name}_extension_tasks.rake"
63
+ load rake_file if File.exist? rake_file
64
+ Rake.application.tasks.map(&:name)
65
+ end
66
+
67
+ def disable
68
+ puts "#{@name} => Removing from Gemfile..."
69
+ current_gemfile = File.read GEMFILE
70
+ updated_gemfile = current_gemfile.sub /gem "radiant-#{@name}-extension".+\n/, ""
71
+ File.open GEMFILE, "w" do |gemfile|
72
+ gemfile.puts updated_gemfile
73
+ end
74
+ bundle
75
+ end
76
+
77
+ def uninstall
78
+ run_tasks({
79
+ :migrate => "VERSION=0",
80
+ :update => :psa
81
+ })
82
+ disable
83
+ end
84
+
85
+ def run_task task, options = ""
86
+ puts "#{@name} => Running #{task} task..."
87
+ if task == "update" and options == :psa
88
+ public_service_announcement `bundle show radiant-#{@name}-extension`.chop
89
+ else
90
+ `rake radiant:extensions:#{@name}:#{task} #{options}`
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,30 @@
1
+ require "ray/extension"
2
+
3
+ module Ray
4
+
5
+ class Git
6
+
7
+ include Extension
8
+
9
+ def install
10
+ if File.exist? "#{Ray::EXT_DIR}/#{@name}"
11
+ raise "The #{@name} extension is already installed"
12
+ end
13
+
14
+ clone
15
+ vendor
16
+ run_tasks
17
+ cleanup
18
+ end
19
+
20
+ def clone
21
+ puts "#{@name} => Cloning..."
22
+ raise "The extension name is required" unless @name
23
+ raise "The repository URI is required" unless @uri
24
+ `git clone --depth=1 --quiet #{@uri} #{Ray::TMP_DIR}/#{@name}`
25
+ FileUtils.rm_rf "#{Ray::TMP_DIR}/#{@name}/.git"
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,44 @@
1
+ require "zip"
2
+ require "ray/extension"
3
+
4
+ # set StringMax to 0 so open-uri always creates a tmp file
5
+ OpenURI::Buffer.send :remove_const, "StringMax"
6
+ OpenURI::Buffer.const_set "StringMax", 0
7
+
8
+ module Ray
9
+
10
+ class Zip
11
+
12
+ include Extension
13
+
14
+ def install
15
+ if File.exist? "#{Ray::EXT_DIR}/#{@name}"
16
+ raise "The #{@name} extension is already installed"
17
+ end
18
+
19
+ download
20
+ extract
21
+ vendor
22
+ run_tasks
23
+ cleanup
24
+ end
25
+
26
+ def extract
27
+ if Dir.glob("#{Ray::TMP_DIR}/*").size != 1
28
+ raise "The file does not exist"
29
+ end
30
+
31
+ archive = Dir.glob("#{Ray::TMP_DIR}/*").first
32
+ ::Zip::ZipFile.open archive do |zip_file|
33
+ zip_file.each do |f|
34
+ f_path = File.join "#{Ray::TMP_DIR}", f.name
35
+ FileUtils.mkdir_p File.dirname f_path
36
+ zip_file.extract f, f_path unless File.exist? f_path
37
+ end
38
+ end
39
+ FileUtils.rm archive
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,62 @@
1
+ require "fileutils"
2
+ require "multi_json"
3
+ require "open-uri"
4
+ require "ray/string"
5
+ require "yaml"
6
+
7
+ module Search
8
+
9
+ def search
10
+ normalize open(@uri).read
11
+ end
12
+
13
+ def cache
14
+ if File.exist? Ray::CACHE
15
+ cache = YAML.load_file Ray::CACHE
16
+ else
17
+ FileUtils.mkdir_p Ray::RAY
18
+ FileUtils.touch Ray::CACHE
19
+ cache = {}
20
+ end
21
+ File.open Ray::CACHE, "w" do |f|
22
+ f.write cache.merge(@results).to_yaml
23
+ end
24
+ return self
25
+ end
26
+
27
+ def output
28
+ output = ""
29
+ if @results.empty?
30
+ output += %Q{
31
+ No extensions matched: #{@query}
32
+ # URI: #{@uri}
33
+ }.lstrip
34
+ else
35
+ @results.each do |extension|
36
+ name = extension.first.to_extension_name
37
+ info = extension.last
38
+ output += %Q{
39
+ #{"-" * 80}
40
+ #{name} (#{info[:version]}) by #{info[:author][0..(78 - " #{name} (#{info[:version]}) by ".size)]}
41
+ #{info[:description].wrap(78, 2)}
42
+ #{info[:homepage]}
43
+ ray install #{name}\n
44
+ }.lstrip
45
+ end
46
+ return output
47
+ end
48
+ end
49
+
50
+ def multiple_choice
51
+ puts output
52
+ print "Which extension do you want to install? "
53
+ choice = STDIN.gets.chomp
54
+ @results[choice]
55
+ end
56
+
57
+ def merge other
58
+ self.results.merge! other.results
59
+ return self
60
+ end
61
+
62
+ end
@@ -0,0 +1,61 @@
1
+ require "fileutils"
2
+ require "ray/search"
3
+ require "ray/string"
4
+ require "yaml"
5
+
6
+ module Ray
7
+
8
+ class Cache
9
+
10
+ include Search
11
+
12
+ attr_reader :query, :uri
13
+ attr_accessor :results
14
+
15
+ def initialize query
16
+ @query = query
17
+ @results = search
18
+ @uri = Ray::CACHE
19
+ end
20
+
21
+ def search
22
+ return {} unless File.exist? Ray::CACHE
23
+ cache = YAML.load_file Ray::CACHE
24
+ results = {}
25
+ cache.each do |extension|
26
+ name = extension.first
27
+ info = extension.last
28
+ if match? name, info[:description]
29
+ results[name] = {
30
+ :author => info[:author],
31
+ :description => info[:description],
32
+ :homepage => info[:homepage],
33
+ :name => name,
34
+ :uri => info[:uri],
35
+ :version => info[:version]
36
+ }
37
+ end
38
+ end
39
+ return results
40
+ end
41
+
42
+ def match? name, description
43
+ if "#{name} #{description}".include?(@query)
44
+ return true
45
+ elsif name.include?(@query.to_extension_name)
46
+ return true
47
+ end
48
+ return false
49
+ end
50
+
51
+ def self.clear
52
+ FileUtils.rm Ray::CACHE
53
+ end
54
+
55
+ def cache
56
+ return self
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,40 @@
1
+ require "ray/search"
2
+
3
+ module Ray
4
+
5
+ class GitHub
6
+
7
+ include Search
8
+
9
+ attr_reader :query, :results, :uri
10
+
11
+ def initialize query
12
+ @query = query
13
+ @uri = "#{Ray::GH_V2_API}/repos/search/radiant+#{@query}"
14
+ @results = search
15
+ end
16
+
17
+ def normalize response
18
+ response = MultiJson.decode response
19
+ results = {}
20
+ response["repositories"].each do |extension|
21
+ results[extension["name"].to_extension_name] = {
22
+ :author => real_name(extension["owner"]),
23
+ :description => extension["description"],
24
+ :homepage => extension["url"],
25
+ :name => extension["name"].to_extension_name,
26
+ :uri => extension["url"],
27
+ :version => "latest"
28
+ }
29
+ end
30
+ return results
31
+ end
32
+
33
+ def real_name owner
34
+ response = open("#{GH_V3_API}/users/#{owner}").read
35
+ MultiJson.decode(response)["name"]
36
+ end
37
+
38
+ end
39
+
40
+ end