I am having trouble using the ABPersonViewController with RubyMotion. The error I'm getting is
Objective-C stub for message setDisplayedPerson:' typev#:^v' not precompiled. Make sure you properly link with the framework or library that defines this message.
I suspect this is due to RubyMotion not casting to the type IOS expects. I think ABPersonCreate() is returning a CFType but the displayedPerson setter is expecting it to be cast as a ABRecordRef (that's just a guess from the error messages)
Here's the sample code to see the problem (based on Apple's QuickContacts sample):
#Rakefile
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
Motion::Project::App.setup do |app|
# Use `rake config' to see complete project settings.
app.name = 'contacts'
app.frameworks += ['AddressBook', 'AddressBookUI']
end
and
# app/app_delegate.rb
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.applicationFrame)
window.rootViewController = UINavigationController.alloc.init
window.rootViewController.wantsFullScreenLayout = true
window.makeKeyAndVisible
true
# This works
add_person('Alex', 'Rothenberg')
# This fails (is it a type casting problem?)
show_person_view_controller('Rothenberg')
end
def show_person_view_controller(name)
anError = nil
address_book = ABAddressBookCreate();
people = ABAddressBookCopyPeopleWithName(address_book, name);
person = people.first
picker = ABPersonViewController.alloc.init.autorelease
picker.personViewDelegate = self
puts "Should this be an AddressBookRef? #{person.inspect}" # => #<__NSCFType:0x8c3bec0>
picker.displayedPerson = person
# The previous line fails
puts "We never reach this line!"
self.navigationController.pushViewController(picker, animated:true)
end
def add_person(first_name, last_name)
error = nil
contact = ABPersonCreate()
ABRecordSetValue( contact, KABPersonFirstNameProperty, first_name, error )
ABRecordSetValue( contact, KABPersonLastNameProperty, last_name, error )
address_book = ABAddressBookCreate()
ABAddressBookAddRecord( address_book, contact, error )
ABAddressBookSave( address_book, error )
end
end
When you run it we are able to add to the address book in the add_person method but it fails in show_person_view_controller on the line picker.displayedPerson = person
$ rake
Build ./build/iPhoneSimulator-5.1-Development
Simulate ./build/iPhoneSimulator-5.1-Development/contacts.app
Should this be an AddressBookRef? #<__NSCFType:0x8da2900>
Objective-C stub for message `setDisplayedPerson:' type `v#:^v' not precompiled. Make sure you properly link with the framework or library that defines this message.
Any suggestions would be appreciated
This will work properly as of RubyMotion 1.12 (run sudo motion update).
Fixed a bug where performing Objective-C methods that accept
CFType objects
would crash the program (ex. [ABPersonViewController setDisplayedPerson:]).
Related
A very common question on StackOverflow with regards to C++/R or C/R package integration is regarding the error in dyn.load(), e.g.
> ## within R
> Error in .Call("function_c") : C symbol name "function_c" not in load table
whereby function_c is some function in C like
SEXP function_c() {
Rprintf("Hello World!\n"); // manually changed
return(R_NilValue);
}
This error come sup due to many types of mistakes, e.g. incorrect compliation, misnamed functions, the user didn't use extern "C" for Cpp code, etc.
Question: Is there any way to view all "available" objects which the user could load via dyn.load() after compilation?
How about the following? I'm not sure it covers everything, but it should be close:
# manipulate search() to get all loaded packages
loadedPkgs = grep('^package:', search(), value = TRUE)
loadedPkgs = gsub('package:', '', loadedPkgs, fixed = TRUE)
# add names here to make the results of lapply pretty
names(loadedPkgs) = loadedPkgs
allCRoutines = lapply(loadedPkgs, function(pkg) {
# see: https://stackoverflow.com/questions/8696158/
pkg_env = asNamespace(pkg)
# this works at a glance
check_CRoutine = function(vname) {
'CallRoutine' %in% attr(get(vname, envir = pkg_env), 'class')
}
names(which(sapply(ls(envir = pkg_env, all = TRUE), check_CRoutine)))
})
The object is a bit long, so I'll just show for one package:
allCRoutines[['utils']]
# $utils
# [1] "C_crc64" "C_flushconsole" "C_menu" "C_nsl" "C_objectSize" "C_octsize" "C_processevents"
# [8] "C_sockclose" "C_sockconnect" "C_socklisten" "C_sockopen" "C_sockread" "C_sockwrite"
What I'm not sure of is that check_CRoutine catches everything we'd consider as relevant to your question. I'm also not sure this covers your main interest (whether these objects can succesfully be fed to dyn.load); perhaps the routines returned here could be passed to dyn.load with a try wrapper?
We are using PMD Copy Paste Detector (CPD) to analyze our C and C++ code.
However, there are a few parts of the code that are very similar, but with a good reason and we would like to suppress the warnings for these parts.
The documentation of PMD CPD only mentions something about annotations, but this will not work for our these languages.
How can I still ignore warnings for specific parts?
Is there a comment to do so perhaps?
[UPDATE] I'm using the following Groovy script to run CPD:
#GrabResolver(name = 'jcenter', root = 'https://jcenter.bintray.com/')
#Grab('net.sourceforge.pmd:pmd-core:5.4.+')
#Grab('net.sourceforge.pmd:pmd-cpp:5.4.+')
import net.sourceforge.pmd.cpd.CPD
import net.sourceforge.pmd.cpd.CPDConfiguration
import java.util.regex.Pattern
def tokens = 60
def scanDirs = ['./path/to/scan', './scan/this/too']
def ignores = [
'./ignore/this/path',
'./this/must/be/ignored/too'
].collect({ it.replace('/', File.separator) })
def rootDir = new File('.')
def outputDir = new File('./reports/analysis/')
def filename_date_format = 'yyyyMMdd'
def encoding = System.getProperty('file.encoding')
def language_converter = new CPDConfiguration.LanguageConverter()
def config = new CPDConfiguration()
config.language = new CPDConfiguration.LanguageConverter().convert('c')
config.minimumTileSize = tokens
config.renderer = config.getRendererFromString 'xml', 'UTF-8'
config.skipBlocksPattern = '//DUPSTOP|//DUPSTART'
config.skipLexicalErrors = true
def cpd = new CPD(config)
scanDirs.each { path ->
def dir = new File(path);
dir.eachFileRecurse(groovy.io.FileType.FILES) {
// Ignore file?
def doIgnore = false
ignores.each { ignore ->
if(it.path.startsWith(ignore)) {
doIgnore = true
}
}
if(doIgnore) {
return
}
// Other checks
def lowerCaseName = it.name.toLowerCase()
if(lowerCaseName.endsWith('.c') || lowerCaseName.endsWith('.cpp') || lowerCaseName.endsWith('.h')) {
cpd.add it
}
}
}
cpd.go();
def duplicationFound = cpd.matches.hasNext()
def now = new Date().format(filename_date_format)
def outputFile = new File(outputDir.canonicalFile, "cpd_report_${now}.xml")
println "Saving report to ${outputFile.absolutePath}"
def absoluteRootDir = rootDir.canonicalPath
if(absoluteRootDir[-1] != File.separator) {
absoluteRootDir += File.separator
}
outputFile.parentFile.mkdirs()
def xmlOutput = config.renderer.render(cpd.matches);
if(duplicationFound) {
def filePattern = "(<file\\s+line=\"\\d+\"\\s+path=\")${Pattern.quote(absoluteRootDir)}([^\"]+\"\\s*/>)"
xmlOutput = xmlOutput.replaceAll(filePattern, '$1$2')
} else {
println 'No duplication found.'
}
outputFile.write xmlOutput
You can define your custom markers for excluding certain blocks from analysis through the --skip-blocks-pattern option.
--skip-blocks-pattern Pattern to find the blocks to skip. Start and End pattern separated by |. Default is #if 0|#endif.
For example the following will ignore blocks between /* SUPPRESS CPD START */ and /* SUPPRESS CPD END */ comments (the comment must occupy a separate line):
$ ./run.sh cpd --minimum-tokens 100 --files /path/to/c/source --language cpp ----skip-blocks-pattern '/* SUPPRESS CPD START */|/* SUPPRESS CPD END */'
Note however, that this will cause the tool perform copy-paste-detection inside code delimited by #if 0/#endif.
After searching through the code of PMD on GitHub, I think I can safely say that this is NOT supported at this point in time (current version being PMD 5.5.0).
A search for CPD-START in their repository, does not show any results within the pmd-cpp directory (see the search results on GitHub).
I know this is a ~3 years old question, but for completeness, CPD started supporting this in PMD 5.6.0 (April 2017) in Java, and since 6.3.0 (April 2018) it has been extended to many other languages such as C/C++. Nowadays, almost all CPD supported languages allow for comment-based suppressions.
The complete (current) docs for comment-based suppression are available at https://pmd.github.io/pmd-6.13.0/pmd_userdocs_cpd.html#suppression
It's worth noting, if a file has a // CPD-OFF comment, but no matching // CPD-ON, everything will be ignored until the end of file.
I don't have any help for CPD. In general, I know about such tools; I don't understand the bit about "warnings".
Our CloneDR tool finds exact and near-miss duplicate code. IMHO, it finds better clones than CPD, because it uses the language syntax/ structure as a guide. [This fact is backed up by a research report done by a third party that you can find at the site]. And it does not issue "warnings".
If there is code that it thinks is involved in a clone, the tool will generate an output report page for the clones involved. But that isn't a warning. There is no way to suppress the reporting behavior. Obviously, if you have seen such a clone and decide it is not interesting, you can mark one of the clone entries with a comment stating that it is an uninteresting clone; that comment will show up in the clone report. (Such) comments have no impact whatsover on what clones are detected by CloneDR, so adding them does not change the computed answer.
I've had this working in a previous version of my application and I tried using the old code, but I think the new sdk has something different going on. I'm simply trying to post a link (that includes an image) to my wall and receiving an "Invalid Parameter" response.
Here is the relevant code (I've also tried PostTaskAsync()...same result):
var client = new FacebookClient(accessToken);
var postParams = new
{
name = "the name",
caption = "the caption",
description = "the description",
link = "http://www.example.com/",
picture = "http://www.example.com/uploadedimages/myimage.jpg"
};
client.Post("me/feed", postParams);
I've tried substituting the object with a Dictionary with the same result. I've tried substituting object with dynamic parameters = new ExpandoObject(); with the same result.
If I post the object with just { message = "this is a test message" } it posts fine so I know that I have permissions to post on my wall. Something just isn't jiving when I try to post the link with the image. I also tried urlencoding the link and the image url and received a different error indicating that the "link/picture URL is not properly formatted".
I stripped out all of the parameters thinking one of them was no longer supported, but still no dice.
Here is the exact exception being thrown:
Facebook.FacebookApiException: (FacebookApiException - #100) Invalid
parameter at Facebook.FacebookClient.ProcessResponse(HttpHelper
httpHelper, String responseString, Type resultType, Boolean
containsEtag, IList`1 batchEtags) at
Facebook.FacebookClient.Api(HttpMethod httpMethod, String path, Object
parameters, Type resultType) at Facebook.FacebookClient.Post(String
path, Object parameters)
I got this sorted out. It turns out the link and the image url have to be in the same domain as the app you're using to post.
EDIT: just to clarify. The domain has to be included in your app's config section (on Facebook) in the "App domains" section at the top.
I'm trying to utilize the build-test-data plugin in my Grails (v2.4.3) app to assist with test data creation for unit testing, but while running my unit tests the plugin cannot find TestDataConfig.groovy to load my specified values (for unique constraint tests, etc).
I've installed the plugin via including it in BuildConfig.groovy:
plugins {
...
test ":build-test-data:2.2.0"
...
}
I've ran the following command to create the TestDataConfig.groovy template, which places the file at \grails-app\conf\:
grails install-build-test-data-config-template
I've followed the general instructions on the plugin wiki to come up with a properly formatted file:
testDataConfig {
sampleData {
'<path>.User' {
def a = 1
username = { -> "username${a++}" }
}
}
}
(Where path is the fully-qualified class name.)
In my tests, I am using the following general format:
import grails.buildtestdata.TestDataConfigurationHolder
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import spock.lang.Specification
import spock.lang.Unroll
#TestFor(User)
#Build(User)
class UserSpec extends Specification {
def setup() {
mockForConstraintsTests(User)
TestDataConfigurationHolder.reset()
user = User.buildWithoutSave()
}
#Unroll
void "test #field must be unique"() {
given: 'a User exists'
user.save(flush: true)
when: 'another User is created with a non-unique field value'
def nonUniqueUser = User.buildWithoutSave()
nonUniqueUser."$field" = user."$field"
then: 'validation fails and the field has a unique constraint error'
!nonUniqueUser.validate()
nonUniqueUser.errors.errorCount == 1
nonUniqueUser.errors.getFieldError("$field").code == 'unique'
where:
field << ['username', '<some other field>']
}
}
But, when the test is run (using IntelliJ IDEA) TestDataConfig.groovy cannot be found via the following method in the plugin:
static Class getDefaultTestDataConfigClass() {
GroovyClassLoader classLoader = new GroovyClassLoader(TestDataConfigurationHolder.classLoader)
String testDataConfig = Holders.config?.grails?.buildtestdata?.testDataConfig ?: 'TestDataConfig'
try {
return classLoader.loadClass(testDataConfig)
} catch (ClassNotFoundException ignored) {
log.warn "${testDataConfig}.groovy not found, build-test-data plugin proceeding without config file"
return null
}
}
So the test continues on without a config file and I do not get uniquely generated data sets.
I've even tried explicitly including the file in Config.groovy:
grails.buildtestdata.testDataConfig = "TestDataConfig"
But, the same method in the plugin shows that Holders.config? is null.
I've looked at a few solutions to a similar problem here on StackOverflow with nothing working in my case; I cannot figure out how to get my app to detect the presence of the TestDataConfig.groovy file.
Any ideas? Thanks so much!
I've been checking out RestKit and the GET works
#client.get("/?amount=5", delegate:self)
Does anyone know how to make a POST and receive the result?
The docs mention that it looks something like this -
#client.post("/ask", params:#paramvar, delegate:self)
What do you encapsulate #paramvar? I have tried it as an array, hash and even nil - however, none of them have yielded any results.
Take a look at the bubble wrap library. It includes some really nice HTTP helpers.
http://bubblewrap.io/
Found an example in the RubyMotion_Cookbook.
https://github.com/IconoclastLabs/rubymotion_cookbook/tree/master/ch_8/06_sendinghttppost
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
#window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
#window.rootViewController = RootController.new
url_string = "http://rubymotion-cookbook.herokuapp.com/post"
post_body = "bodyParam1=BodyValue1&bodyParam2=BodyValue2"
url = NSURL.URLWithString(url_string)
request = NSMutableURLRequest.requestWithURL(url)
request.setTimeoutInterval(30)
request.setHTTPMethod("POST")
request.setHTTPBody(post_body.to_s.dataUsingEncoding(NSUTF8StringEncoding))
queue = NSOperationQueue.alloc.init
NSURLConnection.sendAsynchronousRequest(request,
queue: queue,
completionHandler: lambda do |response, data, error|
if(data.length > 0 && error.nil?)
html = NSString.alloc.initWithData(data, encoding: NSUTF8StringEncoding)
p "HTML = #{html}"
elsif( data.length == 0 && error.nil? )
p "Nothing was downloaded"
elsif(!error.nil?)
p "Error: #{error}"
end
end
)
#window.makeKeyAndVisible
true
end
end
Source:
https://github.com/rubymotion/BubbleWrap
Insallation:-
in console run 'gem install bubble-wrap' or mention 'gem bubble-wrap' in Gemfile
Line to be added in 'app_delegate.rb'file(by this Bubblewrap api is available through out app):-
require 'bubble-wrap/http'
Sample code for syntax:-
BW::HTTP.get("https://api.github.com/users/mattetti", {credentials: {username: 'matt', password: 'aimonetti'}}) do |response|
p response.body.to_str # prints the response's body
end