A ruby wrapper for Google AjaxLibs (jquery, jquery ui, mootools, prototype, swfobject, etc) [Lazy GoogleJsApi Wrapper]
I like using the Google AjaxLibs API. Its cool to not host files when I don't have to, especially ones I know a user has already probably cached from Google anyway (even though Google Page speed busts my balls about too many DNS lookups
).
I do on the other hand hate watching in the bottom of my browser "Waiting for google.com" when using the standard Javascript API for loading the Libraries like so:
1 2 3 4 | <script type="text/javascript" src="http://www.google.com/jsapi?key=INSERT-YOUR-KEY"></script>
<script type="text/javascript">
google.load("jquery", "1.4.2");
</script> |
And you don't have to wait, you can totally do something like:
1 | <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> |
Which is why I wrote this little ruby wrapper. Its nothing special. It just encapsulates all the URLs for the libraries and their versions to allow you to not remember the URL and not have to go looking for the documentation when you start a new app or just need an additional library.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | # Docs: http://code.google.com/apis/ajaxlibs/documentation/index.html # class GoogleJsApi BaseURL = "http://ajax.googleapis.com/ajax/libs".freeze Libraries = { "jquery" => { :versions => %w(1.2.3 1.2.6 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2), :compressed_url => "/jquery/%s/jquery.min.js", :uncompressed_url => "/jquery/%s/jquery.js" }, "jqueryui" => { :versions => %w(1.5.2 1.5.3 1.6 1.7.0 1.7.1 1.7.2), :compressed_url => "/jqueryui/%s/jquery-ui.min.js", :uncompressed_url => "/jqueryui/%s/jquery-ui.js" }, "prototype" => { :versions => %w(1.6.0.2 1.6.0.3 1.6.1.0), :compressed_url => "", :uncompressed_url => "/prototype/%s/prototype.js" }, "scriptaculous" => { :versions => %w(1.8.1 1.8.2 1.8.3), :compressed_url => "", :uncompressed_url => "/scriptaculous/%s/scriptaculous.js" }, "mootools" => { :versions => %w(1.1.1 1.1.2 1.2.1 1.2.2 1.2.3 1.2.4), :compressed_url => "/mootools/%s/mootools-yui-compressed.js", :uncompressed_url => "/mootools/%s/mootools.js" }, "dojo" => { :versions => %w(1.1.1 1.2.0 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1), :compressed_url => "/dojo/%s/dojo/dojo.xd.js", :uncompressed_url => "/dojo/%s/dojo/dojo.xd.js.uncompressed.js" }, "swfobject" => { :versions => %w(2.1 2.2), :compressed_url => "/swfobject/%s/swfobject.js", :uncompressed_url => "/swfobject/%s/swfobject_src.js" }, "yui" => { :versions => %w(2.6.0 2.7.0 2.8.0r4), :compressed_url => "/yui/%s/build/yuiloader/yuiloader-min.js", :uncompressed_url => "/yui/%s/build/yuiloader/yuiloader.js" }, "ext-core" => { :versions => %w(3.0.0 3.1.0), :compressed_url => "/ext-core/%s/ext-core.js", :uncompressed_url => "/ext-core/%s/ext-core-debug.js" }, "chrome-frame" => { :versions => %w(1.0.0 1.0.1 1.0.2), :compressed_url => "/chrome-frame/%s/CFInstall.min.js", :uncompressed_url => "/chrome-frame/%s/CFInstall.js" } }.freeze class << self def include(name, version=nil, compressed=true, validate_version=true) name = name.to_s if lib = GoogleJsApi::Libraries[name] version ||= lib[:versions].last if validate_version && lib[:versions].include?(version) GoogleJsApi.url_for(name, version, compressed) elsif !validate_version GoogleJsApi.url_for(name, version, compressed) else raise Exception, "Invalid version (#{version}) for #{name}" end else raise Exception, "Unknown Google Javascript Library" end end def version_info tmp_version = {} GoogleJsApi::Libraries.each do |k,v| tmp_version[ k ] = v[:versions] end tmp_version end protected def url_for(name, version, compressed) GoogleJsApi::BaseURL + GoogleJsApi::Libraries[ name ][ compressed ? :compressed_url : :uncompressed_url ] % version end end end |
Here are some tests for it if you are interested in how/if it works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | require 'pp' pp GoogleJsApi.version_info # Include the newest version of a library puts GoogleJsApi.include('jquery') # Include a specific version of a library puts GoogleJsApi.include "chrome-frame", "1.0.0" # Include a specific version of a library uncompressed puts GoogleJsApi.include "chrome-frame", "1.0.0", false # Include a specific version of a library w/o validating the version; useful if this goes out of date :P puts GoogleJsApi.include "jquery", "NOT_A_VERSION", false, false begin puts GoogleJsApi.include :jqueryui, "1.0" rescue Exception => e puts "This should blow up..." puts e.message end |
If you want to use it in your Rails or Merb app you can do:
1 2 3 4 5 | # Rails require 'google_js_api' #or whatever you named the file when you dropped it in lib # In your application layout or whatever javascript_include_tag GoogleJsApi.include(:jquery, "1.4.0") |
1 2 3 4 5 | # Merb require 'google_js_api' #or whatever you named the file when you dropped it in lib #in your application layout or where ever require_js GoogleJsApi.include(:swfobject) |
Its simple, its lazy. I like it.
Lower ACL Permissions on Amazon S3 items with ruby
I recently had to change a bunch of permissions on some items on S3. Unfortunately the items were mixed in with items that I didn't want to change the permissions on and the file names are all kinda jumbled, so I couldn't pinpoint what I needed to change by eyeballing the file names.
So I wrote a little ruby method to go in and change something given a key and bucket name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | require 'aws/s3' AWS::S3::Base.establish_connection!( :access_key_id => "YOUR_ACCESS_KEY", :secret_access_key => "YOUR_SECRET_KEY" ) include AWS::S3 def s3_set_public_read(key, bucket) puts "Processing: #{key}" policy = S3Object.acl(key, bucket) policy.grants << ACL::Grant.grant(:public_read) policy.grants << ACL::Grant.grant(:public_read_acp) S3Object.acl(key, bucket, policy) end |
Now I can just run a loop of ActiveRecord objects around that method and convert them all to public read.
If you want a GUI tool for managing S3 stuff, I totally recommend S3Hub. Its a really sexy tool for managing S3.
Expiring rails fragement caches using an expires time instead of a sweeper (expires_in) – (a ‘duh’ post)
So, I'm setting up fragment caching for some stuff, and I honestly don't care about setting up an observer to sweep some stuff. I just want to cache this one slow fragment for like 5 minutes. I've seen these tutorials all over the web that shows people using the expires_in setting to auto-expire cache like so:
1 | Rails.cache.write('test_key', 'test_value', :expires_in => 5.minutes) |
That's great and all, but how the hell do I use it for a Page, Action or Fragment cache? Well you just pass the same :expires_in param and yay it works as long as its a mem_cache_store (although, I did see a hackaroo for file_store)
Even the Rails Guide on caching mentions 'expires_in' but doesn't show how to use it.
1 2 3 | class StupidController < ApplicationController caches_page :whatever, :expires_in => 5.minutes end |
What really got me was when I was trying to use it with a fragment cache. I tried this and it didn't work:
1 | - cache(:action => 'home', :action_suffix => 'advertisements', :expires_in => 10.minutes) do |
Why? Well, the cache method takes two hashes, and if you leave off the curly braces, that expires_in ends up in the first one, which is used for the name... To roll it right do:
1 | - cache({:action => 'home', :action_suffix => 'advertisements'}, :expires_in => 10.minutes) do |
Duh, the more you know.
A Rails rake file for compressing your Javascript with YUI
Here is a quick rake file I threw together to use with my Ruby YUI 2.0 (I-refuse-to-make-a-gem-
edition).
This of course should be used with the Ruby YUI Compressor I posted about the other day.
This script will tar/gzip all of your javascripts just incase something stupid happens. So you have a little safety net.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | require 'fileutils' require 'pathname' namespace :js do desc <<-INFO Output Compressed JavaScript to STDOUT; COMPRESS=ALL to compress all Javascript files that DONT contain ".min." INFO task :yui => :environment do targz() if ENV['COMPRESS'] == 'ALL' Dir[Rails.root.to_s / :public / :javascripts / '**/*.js'].each do |javascript| next if javascript =~ /\.min\./ compress(javascript) end else if File.exist?(Rails.root + "config/yui.yml") javascripts = YAML.load(File.open("config/yui.yml").read)["javascripts"] if !javascripts.blank? javascripts.each {|script| compress(Rails.root + "public/javascripts" + script)} else raise Exception, "No javascript files in config/yui.yml" end else raise Exception, "config/yui.yml Not Found; Do rake js:generate to create one or COMPRESS=ALL to run without a config file" end end end desc "Generate YUI Compressor Config file" task :generate => :environment do config_path = Rails.root + "config/yui.yml" File.open(config_path, "w+") do |f| f.puts <<-CONFIG --- javascripts: - "application.js" - "jquery.js" CONFIG puts config_path end end def targz() tgz_file = "#{Time.now.to_i}.javascripts.tgz" `cd #{Rails.root + "public"}; tar -zcf #{tgz_file} javascripts/` puts "Backed up assets to: #{tgz_file}" end def compress(path) puts "Compressing #{path}" file_handle = File.open(path) compressed_output = YUI.compress_safe file_handle file_handle.close #overwrite the file File.open(path, "w+") { |file| file.puts compressed_output } end end |
Wanna use it?
1. Drop it in your lib/tasks folder or wherever your Rakefile looks
You can compress 'everything' or specific files.
If you want to only compress specific Javascript files do:
1 2 3 | rake js:generate
# Edit your config/yui.yml file
rake js:yui |
If you want to compress "everything" (It actually won't compress files that contain ".min.". You can remove the regexp's if you don't like it.)
1 | rake js:yui COMPRESS=ALL |
Yay, now your raking it in (Pun harhar) w/ your web2.0 yui compressed rails app. Woot woot.
Cory’s Ruby YUI Compressor v 2.0 Simpler, shorter.
So, a while ago I write a Ruby YUI Compressor Wrapper which is still available and works great (although it could use a newer jar file) as far as I know from Mandula's Blog. Some other guy also wrote one that pretty much had the same functionality as my gem. He must have hated it or something, I dunno. Even another guy wrote a wrapper for Closure Compiler if thats your bag.
Anywho, on a new project I'm working on *I just need a inline YUI compressor* and I dont give a damn about anything else like bundling, globbing or whatever. So I ended up throwing together this little (~50 lines less comments) Ruby YUI Compressor to do my dirty work.
I won't make it a gem probably, because if I do someone will just make a ruby-yui-simpler-also gem and put it on digg and get a bigger following
(</sarcasm>)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | require 'open3' require 'stringio' class YUI include Open3 JAR_PATH = File.join(File.dirname(__FILE__),'yuicompressor-2.4.2.jar') class << self # @param io [String|File] # @param options [Hash] - See YUI.cli # @returns String # def compress(io, options = {}) options[:type] ||= :js options[:charset] ||= "utf-8" stdin, stdout, stderr = Open3.popen3( YUI.cli(options) ) stdin.puts streamify(io).read stdin.close my_stderr = stderr.read my_stdout = stdout.read # if compression failed, just output original IO if my_stderr.empty? return my_stdout else raise Exception, my_stderr end end # If any exceptions are raised, the original string will be # returned incase you are compressing stuff during a deploy # and _just_dont_care_ def compress_safe(io, options={}) YUI.compress(io, options) rescue Exception => ex puts ex.message return streamify(io).read end # Sets up the command line options # @param options [Hash] # :jar_path - [String] Path to the jar file, default "./yuicompress-2.4.2.jar" # :charset - [String] default 'utf-8' # :type - [Symbol] Options: js/css, default :js # :line_break - [Fixnum] Column to add line break at # # if the type of compression is JS, then additional options: # :nomunge - [Boolean] do not obfuscate # :preserve_semi - [Boolean] preserve all semicolons # :disable_opt - [Boolean] Disable all micro optimizations # # @returns String # def cli(options) _cmd = ["java -jar #{options[:jar_path] || JAR_PATH}"] _cmd << "--type #{options[:type]}" _cmd << "--charset #{options[:charset]}" if options[:charset] _cmd << "--charset #{options[:line_break]}" if options[:line_break] if options[:type] == :js _cmd << "--nomunge" if options[:nomunge] _cmd << "--preserve-semi" if options[:preserve_semi] _cmd << "--disable-optimizations" if options[:disable_opt] end _cmd.join(' ') end # If a file or a string, treat it like its a stream # # @param string_or_stream [File|String] # @return StringIO # def streamify(string_or_stream) if string_or_stream.respond_to?(:read) string_or_stream.rewind if string_or_stream.eof? string_or_stream else StringIO.new(string_or_stream) end end end #end class << self end |
Wanna use it?
1. Copy the code above, throw it in your lib folder or where ever
2. Download the YUI compressor JAR file and put it in the same directory.
3. Do something like the following...
1 2 3 | YUI.compress("function weebleep(){var cool_variable= 3; return cool_variable;}") #=> "function weebleep(){var a=3;return a};" YUI.compress(File.open( "public/javascripts/application.js")) #=> A bunch of compressed javascript YUI.compress(File.open( "public/stylesheets/application.css"), {:type => :css}) #=> Compressed stylesheet |
Other options include:
:jar_path - [String] Path to the jar file, default "./yuicompress-2.4.2.jar"
:charset - [String] default 'utf-8'
:type - [Symbol] Options: js/css, default :js
:line_break - [Fixnum] Column to add line break at
if the type of compression is JS, then additional options:
:nomunge - [Boolean] do not obfuscate
:preserve_semi - [Boolean] preserve all semicolons
:disable_opt - [Boolean] Disable all micro optimizations
Yay have a blast. Its another compression wrapper.
Ruby Objective-C like Null Pattern
So, I think the objective c null(nil) pattern is pretty cool. I know that lots of people talk about doing it in different ways. Here is my implementation. I'm not keen on having nil catch method missing, because I'm not sure what havoc that may cause in one of the 10million gems I use. I also like the last link above (which I just found when writing this article) except that I dont want to type "try" a million times.
This is my preferred method when dealing with deeply nested messages. Stick this in your lib.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Object def rcall(*method_names) _result = self method_names.collect.each { |mname| if _result.respond_to?(mname) _result = _result.send(mname) else _result = nil break end } _result end end |
Wanna use it?
1 2 3 4 5 6 7 8 9 10 | # In this example, if an of the messages return nil, i'll get a MethodMissing error and I'll be scorned. my_object.first_message.second_message.the_message_whos_value_i_want # The problem is, I dont care if its nil, I have a default, the method is still missing. value = my_object.first_message.second_message.the_message_whos_value_i_want || "Im ok with this being nil" # If chain_message encounters a nil, it just returns nil and you can use standard language logic to default that value # You dont have to do a million if-checks. value = my_object.rcall( :first_message, :second_message, :the_message_whos_value_i_want ) || "Im ok with this being nil" |
Another Example:
1 2 3 4 5 6 7 8 9 10 11 | # Some cool way of finding purchases, be it AR, Datamapper, or whatever, just get an object already purchases = Purchase.all( arbitrary_finder_logic ) # I need to output the name of who added the product on some arbitrary report no one will read # yeah, I know. My validators should have made sure the values were there, I'm just making this up. purchases.each do |purchase| buyer = purchase.rcall(:purchaser, :name) || "John Doe" seller = purchase.rcall(:product, :listor, :name) || "Jack Sales" puts "Buyer: #{buyer}, Seller: #{seller}" end |
Yay, Drying up if-else nil checking statements. High Five.
Symbol to Proc Textmate Find/Replace (reversal) macro
So I know some people are the fans of the symbol to proc in ruby and others aren't. I'm not. I'm all for doing things to save developer time, but I think the symbol to proc thing is super lazy. I see it a lot in projects I work on from other developers and I usually remove it when I see it. So I wrote a textmate find and replace macro to undo them. You can download it here or copy the following source into a file called whatever.tmMacro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>bundleUUID</key> <string>D52BDC31-EFB7-486E-8232-F5B5517E2DF8</string> <key>commands</key> <array> <dict> <key>argument</key> <dict> <key>action</key> <string>replaceAll</string> <key>findInProjectIgnoreCase</key> <false/> <key>findString</key> <string>(\(?)( ?)&:(\w+)( ?)(\)?)</string> <key>ignoreCase</key> <true/> <key>replaceAllScope</key> <string>document</string> <key>replaceString</key> <string>{|i| i.$3 }</string> <key>wrapAround</key> <true/> </dict> <key>command</key> <string>findWithOptions:</string> </dict> </array> <key>keyEquivalent</key> <string>@P</string> <key>name</key> <string>SymbolToProcToNonLazy</string> <key>scope</key> <string>source.ruby</string> <key>useGlobalClipboard</key> <false/> <key>uuid</key> <string>94D8367E-8C6A-4920-AD8D-125CBEFD063D</string> </dict> </plist> |
Once its installed you should be able to do Command-Shift-P and replace all the symbol-to-procs in the current document with their regular proc equivalent.
I've tested it with the following scenarios:
1 2 3 | %w(My super cool array).map &:to_s %w(My super cool array).map( &:to_s ) %w(My super cool array).map(&:to_s) |
If you have any other crazy way of passing in your symbol to proc, let me know. Of course if this macro destroys your computer or sets your hair on fire I take no responsibility, just ask my illegitimate children.
An Excel CSV exporter for ActiveRecord
This is a mix of two blog posts on exporting ActiveRecord data to CSV. This explicitly was designed to export stuff so excel wouldn't freak out.
This strips new lines from any string field, set the BOM and converts the encoding to utf16.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | require "fastercsv" require "iconv" # Excel info from: http://blog.plataformatec.com.br/2009/09/exporting-data-to-csv-and-excel-in-your-rails-app/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+PlataformaBlog+(Plataforma+Blog) # Original post: http://www.brynary.com/2007/4/28/export-activerecords-to-csv # Usage: # Given User is an ActiveRecord model # # Options for Model.to_csv, Array.to_csv, and ActionController::Base#send_csv # # :only - Array, trumps :exclude. Only these attributes will be included instead of all attributes (things listed in :methods will still be sent) # :only => [ :id, :name, :created_at ] # :methods - Array, additional methods to evaluate and add to the CSV response. Note: you can send nested method calls # :methods => [ :to_s, :complex_method, "my.method.on.a.related.object"] # :exclude - Array, attributes to exclude from CSV result # # From ActionController # send_csv User, :only => [:first_name, :email, :created_at] #This will do all records # send_csv User.all(:conditions => ["created_at > ?", some_date]), :only => [:first_name, :email, :created_at] # # From ActiveRecord Model # User.to_csv :only => [ :username, :email, :created_at ], :methods => [ :age, "account.id"] # All users additionally get their related Account#id number # User.all(:limit => 10).to_csv :exclude => [:password, :birthdate] # class ActiveRecord::Base # Shortcut for CSV of whole table def self.to_csv(*args) find(:all).to_csv(*args) end # Get the column headers def self.csv_columns(options={}) tmp_columns = if options[:only] options[:only] #only trumps exclude else self.content_columns.map{|curr_col| curr_col.name } - options[:exclude].map{|curr_col| curr_col.to_s } end tmp_columns + options[:methods].map{|curr_col| curr_col.to_s } end # Record to a row level csv array def to_csv(options={}) self.class.csv_columns(options).map { |curr_col| curr_col = curr_col.to_s #Its a chain of method calls, on intermediary nil, just return nil if !curr_col.index(".") col_val = self.send(curr_col) else col_val = self curr_col.split(".").each {|curr_method| col_val = col_val.send(curr_method) unless col_val.nil?} end col_val.gsub!("\n", " ") if col_val.is_a?(String) # Strip newlines, Appease Excel Gods col_val } end end class Array # Convert an array of objects into a CSV String. def to_csv(options = {}) column_options = { :only => options.delete(:only), :exclude => options.delete(:exclude) || [], :methods => options.delete(:methods) || [] } options = { :col_sep => "\t" # Appease Excel Gods }.merge(options) if all? { |e| e.respond_to?(:to_csv) } header_row = first.class.csv_columns(column_options).to_csv content_rows = map { |e| # Get all the values of non-excluded rows e.to_csv(column_options) }.map{|r| # Call to_csv on the array of row-level values, this will join them into a CSV row r.to_csv(column_options) } ([header_row] + content_rows).join else FasterCSV.generate_line(self, options) end end end # module for extending ActionController module ExcelCSVExporter BOM = "\377\376" #Byte Order Mark, Appease Excel Gods def send_csv(kollection, options={}) filename = options.delete(:filename) || I18n.l(Time.now, :format => :short) + ".csv" content = kollection.to_csv(options) # Appease Excel Gods content = BOM + Iconv.conv("utf-16le", "utf-8", content) send_data content, :filename => filename end end ActionController::Base.send :include, ExcelCSVExporter |
Wanna use it?
1 2 3 4 5 6 7 | class MyCoolController < ActionController::Base def index respond_to {|want| want.csv{ send_csv MyCoolModel.all, :exclude => [:secret_column], :methods => [:complex_method, "related.table.method"]} } end end |
Building curb on Snow Leopard
Had some issues building curb on Snow Leopard today.
It was resulting in something like:
1 2 3 4 5 6 7 | In file included from /opt/local/include/curl/curl.h:44, from curb.h:12, from curb.c:8: /opt/local/include/curl/curlrules.h:144: error: size of array ‘__curl_rule_01__’ is negative /opt/local/include/curl/curlrules.h:154: error: size of array ‘__curl_rule_02__’ is negative lipo: can't open input file: /var/folders/wX/wX64Cb+PGjG-EXuklO+I+k+++TI/-Tmp-//ccKIrqTY.out (No such file or directory) make: *** [curb.o] Error 1 |
It's a quick fix and your on your way to curling stuff...
1 2 3 | sudo port install zlib +universal; sudo port upgrade --enforce-variants openssl +universal; sudo port install curl +universal; |
Then build curb however you were building it before.
Yay, I can scrub other peoples sites now!
Thinking Sphinx cannot find Sphinx
I was getting this error this morning after setting up my new laptop for the project I am working on:
1 2 3 4 5 6 7 8 9 10 11 12 13 | sh: line 1: 326 Trace/BPT trap indexer 2>&1 sh: line 1: 329 Trace/BPT trap /usr/local/bin/indexer 2>&1 Sphinx cannot be found on your system. You may need to configure the following settings in your config/sphinx.yml file: * bin_path * searchd_binary_name * indexer_binary_name For more information, read the documentation: http://freelancing-god.github.com/ts/en/advanced_config.html rake aborted! uninitialized constant MysqlCompat::MysqlRes |
Everyone probably knows this, but I wild-goose-chased trying to figure out if I had a setting wrong in my sphinx.yml file for Thinking Sphinx this morning for like half an hour before I realized what Thinking Sphinx meant about "Sphinx cannot be found on your system." was that the MySQL Development headers weren't installed. I fixed this with a simple port install on Mac.
1 | port install mysql5-devel |
The more you know.