'Error: Cannot open "/home/<...>/billy-bones/=" for reading' while using pry and DataMapper - ruby

So, I'm trying to build a quick console program for my development needs, akin to rails console (I'm using Sinatra + DataMapper + pry).
I run it and launch cat = Category.new(name: 'TestCat', type: :referential). It gives me the following error:
Error: Cannot open "/home/art-solopov/Projects/by-language/Ruby/billy-bones/=" for reading.
What could be the cause of the problem?
console:
#!/usr/bin/env ruby
$LOAD_PATH << 'lib'
require 'pry'
require 'config'
binding.pry
lib/config.rb:
# Configuration files and app-wide requires go here
require 'sinatra'
require 'data_mapper'
require 'model/bill'
require 'model/category'
configure :production do
DataMapper::Logger.new('db-log', :debug)
DataMapper.setup(:default,
'postgres://billy-bones:billy#localhost/billy-bones')
DataMapper.finalize
end
configure :development do
DataMapper::Logger.new($stderr, :debug)
DataMapper.setup(:default,
'postgres://billy-bones:billy#localhost/billy-bones-dev')
DataMapper.finalize
DataMapper.auto_upgrade!
end
configure :test do
require 'dm_migrations'
DataMapper::Logger.new($stderr, :debug)
DataMapper.setup(:default,
'postgres://billy-bones:billy#localhost/billy-bones-test')
DataMapper.finalize
DataMapper.auto_migrate!
end
lib/model/category.rb:
require 'data_mapper'
class Category
include DataMapper::Resource
property :id, Serial
property :name, String
property :type, Enum[:referential, :predefined, :computable]
has n, :bills
# has n, :tariffs TODO uncomment when tariff ready
def create_bill(params)
# A bill factory for current category type
case type
when :referential
ReferentialBill.new params
when :predefined
PredefinedBill.new params
when :computable
ComputableBill.new params
end
end
end
If I substitute pry with irb in the console script, it goes fine.
Thank you very much!
P. S.
Okay, yesterday I tried this script again, and it worked perfectly. I didn't change anything. I'm not sure whether I should remove the question now or not.
P. P. S.
Or actually not... Today I've encountered it again. Still completely oblivious to what could cause it.
** SOLVED **
DAMN YOU PRY!
Okay, so here's the difference.
When I tested it the second time, I actually entered a = Category.new(name: 'TestCat', type: :referential) and it worked. Looks like pry just thinks cat is a Unix command, not a valid variable name.

Not answer to the pry question I just generally hate case statements in ruby.
Why not change:
def create_bill(params)
# A bill factory for current category type
case type
when :referential
ReferentialBill.new params
when :predefined
PredefinedBill.new params
when :computable
ComputableBill.new params
end
end
to:
def create_bill(params)
# A bill factory for current category type
self.send("new_#{type}_bill",params)
end
def new_referential_bill(params)
ReferentialBill.new params
end
def new_predefined_bill(params)
PredefinedBill.new params
end
def new_computable_bill(params)
ComputableBill.new params
end
You could make this more dynamic but I think that would take away from readability in this case but if you'd like in rails this should do the trick
def create_bill(params)
if [:referential, :predefined, :computable].include?(type)
"#{type}_bill".classify.constantize.new(params)
else
#Some Kind of Handling for non Defined Bill Types
end
end
Or this will work inside or outside rails
def create_bill(params)
if [:referential, :predefined, :computable].include?(type)
Object.const_get("#{type.to_s.capitalize}Bill").new(params)
else
#Some Kind of Handling for non Defined Bill Types
end
end

Related

uninitialized constant BikeShare (NameError)

I'm trying to implement some simple testing in rspec for a gem I'm writing. When I comment out describe BikeShare do down to end and run the file, the file loads in and runs successfully. I'm sure it's something tiny I'm missing.
My test file is really simple and looks like this:
require 'spec_helper'
describe BikeShare do
it "should run" do
# response = BikeShare.new
# response.should_be present
end
end
When run, I get the error uninitialized constant BikeShare (NameError) at line 3.
My bikeshare.rb file looks like this, fairly simple:
class BikeShare
def initialize
response = JSON.parse(open("http://bayareabikeshare.com/stations/json").read)
#response = response["stationBeanList"]
end
def get_last_station
#response.last["id"]
end
end
My Rakefile looks like this:
require 'rubygems'
require 'bundler'
Bundler.setup
Bundler::GemHelper.install_tasks
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new do |spec|
# spec.libs << 'lib' << 'spec'
spec.pattern = 'spec/*_spec.rb'
end
task :default => :spec
Your tests arent aware of BikeShare.
You need to require the file that defines your BikeShare class. I dont use rspec but I think that you normally set up your testing environment in spec_helper.rb.

In Ruby/Sinatra, Datamapper's .all works but .get doesn't?

I am trying to take data from a path in Sinatra, and use it to look up a particular record using Datamapper. The Datamapper docs seem to indicate that.
get "/test/:test_path" do
test_get = Intake.get( params[:test_path] )
# Do stuff
erb :blah_blah_blah
end
should find any records associated with the symbol :test_path
This does not work. test_get gets nil.
Meanwhile, what does work is
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
# Do stuff
erb :blah_blah
end
My two questions are:
What am I doing wrong with the .get() call in Datamapper?
Is the .all(:name => value) method slower than .get(), or does it not matter which I use?
Here's a Sinatra script pared down to demonstrate the behavior.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-timestamps'
DataMapper.setup(:default, {:adapter => 'yaml', :path => 'db'})
class Intake
include DataMapper::Resource
property :id, Serial
property :created_at, DateTime
property :test_path, String
end
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
puts 'test_all:' test_all.inspect
test_get = Intake.get( params[:test_path] )
puts 'test_get:' test_get.inspect
"Hello World!"
end
#get only does a lookup based on primary key, with is the id. So
Intake.get(params[:test_path])
looks for something with id params[:test_path], which will fail. Use
Intake.first(test_path: params[:test_path])

Load error when trying to include custom module

Same app, different problem. I'm working on an app using the Dan Benjamin "Meet Sinatra" screencast as a reference. I'm trying to include a custom authentication module, which is housed in a lib folder (lib/authentication.rb). I am requiring that line at the top of my code, but when I try to load the page, it claims there is no such file to load.
Any thoughts?
Here's the top of my main Sinatra file:
require 'sinatra'
require 'rubygems'
require 'datamapper'
require 'dm-core'
require 'lib/authorization'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/entries.db")
class Entry
include DataMapper::Resource
property :id, Serial
property :first_name, String
property :last_name, String
property :email, String
property :created_at, DateTime
end
# create, upgrade, or migrate tables automatically
DataMapper.auto_upgrade!
helpers do
include Sinatra::Authorization
end
And the actual Module:
module Sinatra
module Authorization
def auth
#auth ||= Rack::Auth::Basic::Request.new(request.env)
end
def unauthorized!(realm="Short URL Generator")
headers 'WWW-Authenticate' => %(Basic realm="#{realm}")
throw :halt, [ 401, 'Authorization Required' ]
end
def bad_request!
throw :halt, [ 400, 'Bad Request' ]
end
def authorized?
request.env['REMOTE_USER']
end
def authorize(username, password)
if (username=='topfunky' && password=='peepcode') then
true
else
false
end
end
def require_admin
return if authorized?
unauthorized! unless auth.provided?
bad_request! unless auth.basic?
unauthorized! unless authorize(*auth.credentials)
request.env['REMOTE_USER'] = auth.username
end
def admin?
authorized?
end
end
end
Then, on any of the handlers I want to protect, I put "require_admin."
Assuming you're using Ruby 1.9, the default $LOAD_PATH no longer includes the current directory. So while statements like require 'sinatra' work just fine (because those gems are in $LOAD_PATH), Ruby doesn't know that your lib/authorization file is located relative to your main Sinatra file.
You can add the Sinatra file's directory to the load path, and then your require statements should work fine:
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'sinatra'
require 'rubygems' # Not actually needed on Ruby 1.9
require 'datamapper'
require 'dm-core'
require 'lib/authorization'
Personnaly, I use a "relative" path since I work with Ruby 1.9.2 :
require 'sinatra'
require 'rubygems' # Not actually needed on Ruby 1.9
require 'datamapper'
require 'dm-core'
require './lib/authorization'
But I never check what would happen if my code should work on Ruby 1.8.6 again.

In Sinatra(Ruby), how should I create global variables which are assigned values only once in the application lifetime?

In Sinatra, I'm unable to create global variables which are assigned values only once in the application lifetime. Am I missing something? My simplified code looks like this:
require 'rubygems' if RUBY_VERSION < "1.9"
require 'sinatra/base'
class WebApp < Sinatra::Base
#a = 1
before do
#b = 2
end
get '/' do
puts #a, #b
"#{#a}, #{#b}"
end
end
WebApp.run!
This results in
nil
2
in the terminal and ,2 in the browser.
If I try to put #a = 1 in the initialize method, I'm getting an error in the WebApp.run! line.
I feel I'm missing something because if I can't have global variables, then how can I load large data during application instantiation?
before do seems to get called every time there is a request from the client side.
class WebApp < Sinatra::Base
configure do
set :my_config_property, 'hello world'
end
get '/' do
"#{settings.my_config_property}"
end
end
Beware that if you use Shotgun, or some other Rack runner tool that reloads the code on each request the value will be recreated each time and it will look as if it's not assigned only once. Run in production mode to disable reloading and you will see that it's only assigned on the first request (you can do this with for example rackup --env production config.ru).
I ran into a similar issue, I was trying to initialize an instance variable #a using the initialize method but kept receiving an exception every time:
class MyApp < Sinatra::Application
def initialize
#a = 1
end
get '/' do
puts #a
'inside get'
end
end
I finally decided to look into the Sinatra code for initialize:
# File 'lib/sinatra/base.rb', line 877
def initialize(app = nil)
super()
#app = app
#template_cache = Tilt::Cache.new
yield self if block_given?
end
Looks like it does some necessary bootstrapping and I needed to call super().
def initialize
super()
#a = 1
end
This seemed to fix my issue and everything worked as expected.
Another option:
helpers do
def a
a ||= 1
end
end
Building on Theo's accepted solution, it is also possible to do:
class App < Sinatra::Application
set :blabla, ''
namespace '/b' do
get '/baby' do
# do something where bouh is assigned a value
settings.blabla = 'bouh'
end
end
namespace '/z'
get '/human' do
# settings.blabla is available here with newly assigned value
end
end
end
You could use OpenStruct.
require 'rubygems'
require 'sinatra'
require 'ostruct'
configure do
Struct = OpenStruct.new(
:foo => 'bar'
)
end
get '/' do
"#{Struct.foo}" # => bar
end
You can even use the Struct class in views and other loaded files.

Webrat Mechanize outside of Rails

I'm trying to use Webrat in a standalone script to automate some web browsing. How do I get the assert_contain method to work?
require 'rubygems'
require 'webrat'
include Webrat::Methods
include Webrat::Matchers
Webrat.configure do |config|
config.mode = :mechanize
end
visit 'http://gmail.com'
assert_contain 'Welcome to Gmail'
I get this error
/usr/lib/ruby/gems/1.8/gems/webrat-0.6.0/lib/webrat/core/matchers/have_content.rb:57:in 'assert_contain': undefined method assert' for #<Object:0xb7e01958> (NoMethodError)
assert_contain and other assertions are methods of test/unit, try to require it and use webrat from inside a test method:
require 'test/unit'
class TC_MyTest < Test::Unit::TestCase
def test_fail
assert(false, 'Assertion was false.')
end
end
anyway i haven't tested it but I have a working spec_helper for rspec if this can interest you:
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
require 'spec/rails'
require "webrat"
Webrat.configure do |config|
config.mode = :rails
end
module Spec::Rails::Example
class IntegrationExampleGroup < ActionController::IntegrationTest
def initialize(defined_description, options={}, &implementation)
defined_description.instance_eval do
def to_s
self
end
end
super(defined_description)
end
Spec::Example::ExampleGroupFactory.register(:integration, self)
end
end
plus a spec:
# remember to require the spec helper
describe "Your Context" do
it "should GET /url" do
visit "/url"
body.should =~ /some text/
end
end
give it a try I found it very useful (more than cucumber and the other vegetables around) when there is no need to Text specs (features) instead of Code specs, that I like the most.
ps you need the rspec gem and it installs the 'spec' command to execute your specs.

Resources