I've been thinking about learning how to make simple Mac OS X applications based on web-technology and I came across node-webkit which seems compelling. However, I've recently invested in learning the basics of Sinatra/Ruby and I wanted to stay on that course.
Is there a "node-webkit equivalent" for developers who use Sinatra? Or, is there a recommended way to use the Sinatra framework (or Ruby) to build OS X apps that are essentially web wrappers?
Sinatra is a server-side framework.
Contrary to Node-webkit which is on client side.
If you need to interact with a server, you can still use sinatra (as well as node.js, php, ...) on your server.
But if you are looking for a framework like sinatra on node.js, you should look into Express.js : https://npmjs.org/package/express
Node-webkit can use file or http, and which to use depends on your needs. The majority of the time you shouldn't need to, Node-webkit runs completely client-side using only HTML, javascript, and css. You certainly can initialize a local webserver when Node-webkit loads, but first try making a basic "Hello World" application to learn how it works.
If you still think you need to spin up a web server, then the code might look something like this (I'm using Express.js):
// Retrieve libraries...
var expressPort = 6014
var NodeWebkit = require('nw.gui');
// Call focus to application...
NodeWebkit.Window.get().focus();
// Instantiate the Express Server...
var spawn = require("child_process").spawn;
spawn("node", ['./server/server', expressPort]);
// Request director page...
window.location.replace('http://localhost:'+expressPort);
In order to use the Node-webkit features from a page on localhost you will also need to add the following line beneath the root of your package.json:
node-remote": "<local>
Note: While this does work, you must really consider whether it makes sense. In other words, is you application fully self-contained? If nothing will access that content except the application then you don't need it.
For my application I am using Node-webkit as an admin console for creating/managing broadcasts. (hence the local webserver)
Nw is not a web framework. Nw does not use a http protocol; it does use a file protocol.
Nw is composed of chromium and nodejs, which allows you to run both DOM and node.js stuff -- without setting up a web server.
Related
In my company, we're using Spring Boot to implement backend API and React to implement frontend including Web interface and Android/iOS apps.
Since our product is an Enterprise software, customers actually have to pay to get the latest backend API to deploy on their own servers. However, our mobile apps are regularly updated on the App Store. This leads to a situation where the mobile apps on end-users' devices may be the newer version while the backend API on the customer's machine is the older one. We plan to support up to 3 minor version backward, meaning FE 5.4 will support up to backend 5.2.
The backend does have an endpoint to return the current version number. However, I'm a bit clueless as to how our frontend implementation can maintain backward compatibility with older API versions as we add new features and may introduce breaking changes in backend API.
I completely understand there might not any beautiful solutions for this problem. I'm hoping if you've gone through this pain, you can share your experiences about what you've tried, the final approach that you took and the potential pitfalls to look out for.
I'm sure myself and other people who's running into this issue would be really grateful :).
Your solution will be similar to any frontend solution that uses Feature Toggle but I can already imagine that it will not be pretty.
Basically inside your code you'll have a lot of if/else statements or some form of wrapper that does the same underneath for every piece of UI/logic/functionality that is a breaking change on version upgrade.
I'd suggest that for every layers that you have (UI, logic, API call) you should start to have switches based on version returned by backend. You'll end up with a lot of redundant looking codes and a lot of codes that looks like this. (if you support only two versions. Use switch if you have more versions)
render() {
{version === "1.0.0" ? <VersionA /> : <VersionB/>}
}
You can however, write a utility method that wraps and returns different components based on versions. By doing that you can more easily remove components that you no longer need to support in the future.
const versionSwitcher = (version, ...Components) => {
switch (version) {
case "1.0.0":
return Components[0];
case "1.1.0":
return Components[1];
}
}
This of course, increases complexity throughout all layers but given your case I can't see it being simple. A good thing to do is to try to keep your own viewModel and never pass response from API directly into component. That reduces the coupling between API and your components and will make this a little easier.
I am writing a Padrino app which will expose a few services via REST apis. I need to version the apis. I found this answer which explains how to version an api such that the version is embedded in the uri. I would rather put my version info in the Accept header or some other HTTP header (let's not go into the whole embed-in-uri vs put-in-header debate for now). Is there an idiomatic way of implementing this in a Padrino controller? I would like to avoid littering version checks in all my routes. Is there any way I can put the check in a central place (DRY) or - better still - let Padrino take care of this for me with some magical directives?
Try to implement (ofc, w/o 'v1' in url) this.
Also found that. It should work since Padrino is the little bro of Sinatra.
Can't test for the moment. Please keep me aware !
I wrote my own FaceBook library that uses actual Curl requests, not libcurl.
Is there a way to test it? I'm asking this because most solutions involve using something like fakeweb which as far as I can tell will not work here.
The existing code can be found on my github page.
One approach would be to use a different host/port in test mode (eg localhost:12345)
Then in your test run a sinatra or webrick servlet on that port that you configure to respond to the requests your code should be making
You could mock Request.dispatcher with an expected behavior, pretty much like Fakeweb would do.
There are a few examples on this file, specially https://github.com/chrisk/fakeweb/blob/master/lib/fake_web/ext/net_http.rb#L44.
When running your tests/specs, monkey-patch the run method of your Request class to hook into the Marston VCR library. See the existing library_hooks subdir for examples and ideas on how to do this -- the fakeweb implementation is a good place to start.
VCR works well with live services like Facebook's because it captures interactions "as is", and VCRs can be easily re-recorded when the services change.
I'm running into problems with your library, however. You need to require the cgi and json libraries; it also looks like it requires a Rails environment (it's failing to find with_indifferent_access on Hash).
I was hoping to make a Rails app usable both as an Engine and as a standalone Application.
Specifically, I have a nascent app which I'd like to plug in to a customer's site, but ideally, I'd like to just as easily use the app as a standalone system. However, if config/environments/*.rb exist in the enginified version of my app, I get an Uninitialized Constant error at the time the app that I'm having take a dependency on my engine starts up; Rails complains that the MyEngineModule::Application constant can't be found in development.rb, which I think is simply a load order issue, since this does NOT occur when I run the app standalone. If I delete development.rb, the original initializers that reference my MyEngineModule::Application complain, so then I tried to delete those, and all is well.
Great, except that the original app doesn't work, since its configuration is gone.
Is there some tweak I can make to the initialization load order (or load paths, in the Engine < Rails::Engine class definition) that would prevent the original configs and initializers from being loaded when in an engine context, and allow me to leave them in place for the app context?
The simpler answer is probably this, but I'm feeling stubborn, and would like to know what it would take to make my original goal possible:
extract the code for MyEngine into an engine, remove the config/environments/* files and config/initializers/* files, and make the client app depend on this.
Make a "new" minimalist app depend on MyEngine, and move the environment files and initializers to NewApp.
Assuming I feel some unnatural compulsion to keep my original application runnable as it was, if I want to prevent the "engine" from loading the "application" configuration, what's the best way to handle that? I presume this is only really a problem during development, because I can prevent the environments/*.rb files from being pulled into the gem itself, but I like being able to test locally while I'm developing the engine and its client app.
Continuing my tradition of answering my own esoteric questions, it seems like one passable alternative is to include a guard clause in the engine's environments/*.rb and the initializers that goes something like this:
if defined? CuteEngine::Application
CuteEngine::Application.configure do
config.whatever = something
end
end
This gets around the problem of having two Rails::Application objects at a relatively small cost. Not very happy about it, but I'll live.
Bumping this for new comers.
Rails 3.1 comes with mountable engines, which sounds like exactly what you are describing. The docs aren't great for converting existing code, but it looks like this will do what you want:
module CuteEngine
class Engine < ::Rails::Engine
isolate_namespace CuteEngine
end
end
In your other app's routes.rb file, you'll add:
mount CuteEngine::Engine, at: "/cuteness"
http://edgeguides.rubyonrails.org/engines.html#mounting-the-engine
http://railscasts.com/episodes/277-mountable-engines
I have written a Firefox extension that catches when a particular URL is entered and does some stuff. My main app launches Firefox with this URL. The URL contains sensitive information so I don't want it being stored in the history.
I'm concerned about the case where the extension is not installed. If its not installed and Firefox gets launched with the sensitive URL, it will get stored in history and there's nothing I can do about it. So my idea is to use a bookmarklet.
I will launch Firefox with "javascript:window.location.href='pleaseinstallthisplugin.html'; sensitiveinfo='blahblah'".
If the extension is not installed they will get redirected to a page that tells them to install it and the sensitive info won't get stored in the history. If the extension IS installed it will grab the information in the sensitiveinfo variable and do its thing.
My question is, can the bookmarklet call a method in the extension to pass the sensitive info (and if so, how) or can the extension catch when javascript is being called in the bookmarklet?
How can a bookmarklet and Firefox extension communicate?
p.s. The alternative means of getting around this situation would be for my main app to launch Firefox and communicate with the extension using sockets but I am loath to do that because I've run into too many issues over the years with users with crazy firewalls blocking socket communication. I'd like to do everything without sockets if possible.
As far as I know, bookmarklets can never access chrome files (extensions).
Bookmarklets are executed in the scope of the current document, which is almost always a content document. However, if you are passing it in via the command line, it seems to work:
/Applications/Namoroka.app/Contents/MacOS/firefox-bin javascript:alert\(Components\)
Accessing Components would throw if it was not allowed, but the alert displays the proper object.
You could use unsafeWindow to inject a global. You can add a mere property so that your bookmarklet only needs to detect whether the global is defined or not, but you should know that, as far as I know, there is no way to prohibit sites in a non-bookmarklet context from also sniffing for this same global (since it may be a privacy concern to some that sites can detect whether they are using the extension). I have confirmed in my own add-on which injects a global in a manner similar to that below that it does work in a bookmarklet as well as regular site context.
If you register an nsIObserver, e.g., where content-document-global-created is the topic, and then unwrap the subject, you can inject your global (see this if you need to inject something more sophisticated like an object with methods).
Here is some (untested) code which should do the trick:
var observerService = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
observerService.addObserver({observe: function (subject, topic, data) {
var unsafeWindow = XPCNativeWrapper.unwrap(subject);
unsafeWindow.myGlobal = true;
}}, 'content-document-global-created', false);
See this and this if you want an apparently easier way in an SDK add-on (not sure whether SDK postMessage communication would work as an alternative but with the apparently same concern that this would be exposed to non-bookmarklet contexts (i.e., regular websites) as well).