moonmaster9000 / dupe Goto Github PK
View Code? Open in Web Editor NEWBDD your (ActiveResource compatible) services from the client-side, before they exist.
BDD your (ActiveResource compatible) services from the client-side, before they exist.
I'm running into an issue where I want to override a GET
request's response xml with a little customization, but I don't seem to be able to.
From script/console
, here's what I'm trying to do:
require 'dupe'
class Quote < ActiveResource::Base
self.prefix = '/my_namespace/'
end
Dupe.define :quote
Get %r{^/my_namespace/quotes/(\d+)\.xml$} do |quote_id|
raise "hi!"
end
dupe_quote = Dupe.create(:quote)
And finally:
>> Quote.find(dupe_quote.id)
=> #<Quote:0x211680c @attributes={"id"=>1}, @prefix_options={}>
I would have expected it to raise my error. My personal usage for this is somewhat more complicated, but I've made this simple example to demonstrate the problem.
Looking at the log...
>> puts Dupe.network.log.pretty_print
Logged Requests:
Request: GET /my_namespace/quotes/1.xml
Response:
1
And inspecting the defined mocks:
>> Dupe.network.mocks
=> {:get=>[#<Dupe::Network::GetMock:0x213679c @response=#<Proc:0x02137430@(eval):5>, @url_pattern=/^\/my_namespace\/quotes\.xml$/>, #<Dupe::Network::GetMock:0x21366fc @response=#<Proc:0x02137160@(eval):10>, @url_pattern=/^\/my_namespace\/quotes\/(\d+)\.xml$/>, #<Dupe::Network::GetMock:0x2131508 @response=#<Proc:0x02131594@(irb):7>, @url_pattern=/^\/my_namespace\/quotes\/(\d+)\.xml$/>], :post=>[#<Dupe::Network::PostMock:0x21366d4 @response=#<Proc:0x02136f1c@(eval):15>, @url_pattern=/^\/my_namespace\/quotes\.xml$/>], :put=>[#<Dupe::Network::PutMock:0x21366ac @response=#<Proc:0x02136b98@(eval):20>, @url_pattern=/^\/my_namespace\/quotes\/(\d+)\.xml$/>], :delete=>[#<Dupe::Network::DeleteMock:0x2136684 @response=#<Proc:0x021368b4@(eval):25>, @url_pattern=/^\/my_namespace\/quotes\/(\d+)\.xml$/>]}
Of specific note is the url patterns:
>> Dupe.network.mocks[:get].map{|mock| mock.url_pattern}
=> [/^\/my_namespace\/quotes\.xml$/, /^\/my_namespace\/quotes\/(\d+)\.xml$/, /^\/my_namespace\/quotes\/(\d+)\.xml$/]
Notice how there are two identical url patterns there (originally I was doing this with a slightly different url pattern - didn't have the ^$
symbols and was using the character class [0-9]
instead of \d
, but tried duplicating the pattern to see if it would overwrite -- it didn't, as you can see). It seems as though the dupe definition is creating it's normal default GET
mock, but no matter what I do I can't override it with my own. Is there a way to force certain calls to not create their auto-mocks? Or is there some other way to do this?
How does it decide which url pattern/response to follow? It should just be the last one defined shouldn't it? I figure that the Dupe.define :quote
would make a url pattern, but since I define mine after that one it should catch on my definition and not fall through to the automatically-generated one.
Edit: Added the call to Dupe.network.log.pretty_print
The readme indicates Rails 3 support is to be added and yet installing the gem installs activesupport and activemodel 3. I tried 0.3.5 but that's the same. Does this gem still work with Rails 2.3?
Thanks.
ActiveResource requests for a collection of results thrown an exception when that maps to a Dupe.find that returns an empty array:
Dupe.define :author
class Author < ActiveResource::Base; self.site = ''; end
Author.find :all
==> You have a nil object when you didn't expect it!
The error occurred while evaluating nil.__model__ (NoMethodError)
The expected result was:
Author.find :all
==> []
Rails 3.1 is right around the corner but I wasn't able to use Dupe with the edge version of Rails. I got a lot of errors.
in version 0.4.8, if i have a definition that has a lazy attribute that returns a Dupe record, that record is actually a duped version of the original record created - meaning that i can change the value of that record without actually affecting the original record in memory (the only people will find through a Dupe.find).
e.g.:
Dupe.define :book do |book| book.genre do Dupe.find_or_create :genre, :name => 'Sci-fi' end end b = Dupe.create :book b2 = Dupe.create :book b.genre.name = 'Science Fiction' puts b2.genre.name # should return 'Science Fiction', but instead still returns 'Sci-fi'
I've defined a simple dupe using the following:
Dupe.define(:transformation)
After creating a record and then doing Transformation.all, I get a result which is as expected. But when I do Transformation.find(id) using an id I know exists I get the error below.
undefined method `body' for #<Hash:0x00000003578cf0>
I'm using Rails 4.0.4 which uses ActiveResource 4.0.0. I'm using my own branch to allow the use of Rails 4 via the gemspec but maybe it's not that simple. simmogs@54a5304
When my ActiveResource objects are configured to use non-root URLs like http://host/api/v1
, Dupe doesn't know how to create the standard CRUD intercepts. It knows to look at at the right URL when .find()
ing, but returns this error:
HANDLER ERROR: No mocked service response found for '/api/v1/users/1.xml'
This is easily solved on my side by simply removing everything after http://host/
, but it would be nice if there was built in support for this.
When trying to define a dupe of 'address' it doesn't seem to be interpreting it correctly (maybe something to do with the pluralization parser?)
>> Dupe.define :address do |addr|
?> addr.name
>> addr.uniquify :address1
>> addr.address2
>> addr.city "Denver"
>> addr.region "CO"
>> addr.postal_code "55555"
>> addr.phone "5554443210"
>> addr.phone2
>> addr.fax
>> addr.main_address false
>> addr.addressable_id {Dupe.create(:profile).id}
>> addr.addressable_type "Profile"
>> addr.lat
>> addr.lng
>> end
>> Dupe.create(:address)
=> <#Duped::Addres id=1>
Notice how it's stripping one of the 's' characters off the end of the created object, and not reading in any of the default properties defined.
However, when I add an extra 's'... it decides to create the object properly.
>> Dupe.create(:addresss) # Notice the three 's' characters
=> <#Duped::Address lng=nil city="Denver" main_address=false region="CO" addressable_id=<#Duped::Profile id=1> postal_code="80234" name=nil phone="5554443210" address1="address 1 address1" addressable_type="Profile" phone2=nil lat=nil address2=nil id=1 fax=nil>
steps to reproduce:
require 'dupe' Dupe.define :book do |book| book.authors [] end b = Dupe.create :book a = Dupe.create :author b.authors << a # at this point, b.authors includes a # however, if you create a new book, it will also have that author in it Dupe.create :book
I try your sample
irb# require 'dupe'
irb# Dupe.create :author, :name => 'Monkey', :published => true
irb# Dupe.create :author, :name => 'Tiger', :published => false
irb# class Author < ActiveResource::Base; self.site = '';self.format = :xml; end
irb# Get %r{/authors/published.xml} do
irb# Dupe.find(:authors) {|a| a.published == true}
irb# end
irb# Author.find :all, :from => :published
I have this message
URI::BadURIError: both URI are relative
Env :
irb --version
irb 0.9.6(09/06/30)
rails -v
Rails 3.1.0.rc1
ruby -v
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]
I'd love to use Dupe against JSON API's. It looks like the intercept mocks match for urls ending in ".xml" explicitly. I don't know what else is involved.
ARes in Rails 3.1, seems to default to JSON also.
The gem seems to bug with class names such as Person, where it'd have to make conversions from and to people.
The following code works perfectly for Company, but screws up for Person:
http://gist.github.com/480120
Any plan to add ability to name the definition that are different than the model it would create, like in Factory Girl.
Something like:
Dupe.define :fancy_recipe, :class => Recipe do |t|
t.name "Fancy Recipe"
end
I think the usage of this is so one can create a factory of a particular pattern easily.
I'm trying to use dupe for cucumber (and soon rspec, but i'll do cucumber for now) but am running into some problems with custom mock declarations. For instance, let's say I run this in the script/console command window:
require 'dupe'
Post %r{/sessions\.xml} do |params|
user = Dupe.find(:user){|u| u.email == params["email"] && u.encrypted_password == params["password"]}
raise ActiveResource::UnauthorizedAccess.new(DupeUnauthorizedAccess.new) if user.nil?
Dupe.create(:session, :id => user.id)
end
# This is just so I have something with a 'code' method without having to mock a full 401 response object for that ActiveResource::UnauthorizedAccess above
class DupeUnauthorizedAccess
def code
401
end
end
Now here's what happens: a Post
request should (as I see it) always go through this method and evaluate what to return as appropriate. As long as the posted params email
and password
match up with a dupe user's email
and encrypted_password
respectively, then a Session object should be returned with an id
identical to the user found. If no such user is found (the email or password are incorrect), then perform an ActiveResource::UnauthorizedAccess
error.
This works quite flawlessly...on all calls to Session.create(options) up to and including the first successful one, but any calls after that skip the Post method I defined entirely. Continue in that same console session with this code to see what I mean:
Dupe.create(:user, :email => '[email protected]', :encrypted_password => 'password')
Session.create(:email => '[email protected]', :password => 'bad_password')
This should raise an ActiveResource::UnauthorizedAccess error. It does for me, and that's what we want (the passwords didn't match, see). Now, let us continue.
Session.create(:email => '[email protected]', :password => 'password')
This one was our first 'successful' response from that post method. We can even see that the only thing it made in our sessions model was an id:
>> Dupe.find(:sessions)
=> [<#Duped::Session id=1>]
However, now any calls to create a session will succeed regardless of whether or not the password matches. We will do the exact same call we did a couple of lines ago that did raise an error (we'll print our users out first just to make sure):
>> Dupe.find(:users)
=> [<#Duped::User email="[email protected]" encrypted_password="password" id=1>]
>> Session.create(:email => '[email protected]', :password => 'bad_password')
=> #<Session:0x20aa3f0 @attributes={"id"=>2, "password"=>"bad_password", "email"=>"[email protected]"}, @prefix_options={}>
From our printed users, we can see that the password was 'password. Then we run the create method (which should be sending to that Post mock, no?), which should be giving us that same ActiveResource::UnauthorizedAccess
error that we saw earlier...but it passed instead. You can see the extent of the failure in the sessions find:
>> Dupe.find(:sessions)
=> [<#Duped::Session id=1>, <#Duped::Session email="[email protected]" password="bad_password" id=2>]
Our first one is there, but the second one is too somehow...and with more than just an id
(and with the wrong id
at that)
I've put some raises all over the Post method to see if it got in there at all, but as long as the Post succeeds once, any subsequent calls to it regardless of the params will always create a new session, with not necessarily the properties that I want.
At present, when I run 'gem server' and access the rdoc for this gem, active_resource.rb is loaded into the main frame. It should be the README.
It seems that while Dupe is loaded, all ActiveResource requests are processed by Dupe.
I think it would be interesting that Dupe act as a backup so that normal requests with different uri than those defined with Dupe keep being processed as normal active resources. If a NoResource error is raised by ActiveResource, then Dupe is asked for a mock resource corresponding.
That way, resources can be mocked while others are kept real.
I'm getting this error:
Dupe::Network::Mock::ResourceNotFoundError in 'User#find_by_id should return nil if the id is not correct'
Failed with 404: the request '/v1/users/202.xml' returned nil.
But my code in the model looks like this:
def self.find_by_id(user_id)
find(user_id)
rescue ActiveResource::ResourceNotFound
nil
end
I find it odd that Dupe doesn't throw up ActiveResource::ResourceNotFound
errors since that's what one would be rescuing in the code. My spec doesn't work because the error is being raised, even though I'm rescuing the real-world exception.:
it "should return nil if the id is not correct" do
User.find_by_id(@user.id + 200).should be_nil
end
Sorry if it feels like I'm being nitpicky with dupe! I reaaaally love dupe :) It's great and does just about everything I need. But there are these couple things I feel it's missing to be really stellar
When I try to do this:
Dupe.create :author, :name => 'Tiger', :published => false
class Author < ActiveResource::Base; self.site = ''; end
Get %r{/authors/published.xml} do
Dupe.find(:authors) {|a| a.published == true}
end
Author.find :all, :from => :published
Finally I get: URI::BadURIError: both URI are relative
from lib/dupe/active_resource_extensions.rb:19:in `get'
I am using rails 3.0.5 and dupe '0.6.0', and ruby 1.8.5... Should I use ruby 1.9.X?
I use site.prefix but Dupe doesn't take account of this
ActiveResource::InvalidRequestError Exception: Could not find a response recorded for <POST: /api/resource.json ......................
Expected behavior:
irb# require 'dupe'
==> true
irb# Dupe.create :author, :test => 1, 'test' => 2
==> <#Duped::Author test=2 id=1>
Actual behavior:
irb# require 'dupe'
==> true
irb# Dupe.create :author, :test => 1, 'test' => 2
==> <#Duped::Author test=1 test=2 id=1>
I am currently developing a service that acts as a middle-man for two other services. On either side, we have Foo model and the middle transports them across. We accomplished the same-name model problem in our middle man by subclassing our ActiveResource models like so:
module LeftSide::Foo class Foo < ActiveResource::Base self.site = CONFIG['api']['left_side_url'] end end
module RightSide::Foo class Foo < ActiveResource::Base self.site = CONFIG['api']['right_side_url'] end end
Currently I am getting the error:
HANDLER ERROR: Undefined prefix RightSide found /usr/local/lib/ruby/1.8/rexml/parsers/baseparser.rb:389:in `pull' /usr/local/lib/ruby/1.8/set.rb:195:in `each' /usr/local/lib/ruby/1.8/set.rb:195:in `each_key' /usr/local/lib/ruby/1.8/set.rb:195:in `each'
When trying to execute this code in my steps:
Dupe.create "RightSide::Foo", :a_value => '1234' Dupe.find('RightSide::Foo') {|b| a_value == '1234'}
The other issue we'll have is the fact that API calls are reduced down to the path. In both my LeftSide and RightSide API's, the routes are the same. I haven't had a chance to test conflicts between model URLs yet, but I have a feeling this is going to fail.
Dupe works great in my Cucumber features, but I haven't found any example of how to use it with Rspec. Can it hook into ActiveResource::HttpMock somehow?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.