Code Monkey home page Code Monkey logo

bacon.js's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bacon.js's Issues

Unplug stream off bus

Hi! For example, I have a class with bus:

class SomeClass
  constructor: (@node) -> # @node istanceof jQuery
    @bus = new Bacon.Bus()

  render: (data) ->
    @node.get(0).innerHTML = "<!--some template HTML rendered by data-->"
    @stream = @node.children().asEventStream("click")
    .map(".currentTarget")

    @bus.plug @stream

  reRender: (data) ->
    @node.get(0).innerHTML = ""
    #???
    render (data)

This is what I have to do: I need to re-render @node contains (it calls by another event) so I need to unplug current stream and replug it in render function call inside reRender function (there is subscriber on bus, so I don't need to catch events of multiple streams; same time I can't create stream until @node doesn't have any children to listen to).

How to unplug stream inside reRender function or how to improve this code?

Thanks

Do not mutate arrays into objects when using .combineTemplate()

The array in key is converted into object with array indices as keys: {0: {x: 1}, 1: {x: 2}}

Bacon.combineTemplate({
  key: [{ x: 1 }, { x: 2 }]
})

Temporary fix to prevent this:

var constArray = Bacon.constant([{ x: 1 }, { x: 2 }])
Bacon.combineTemplate({ key: constArray })

Rename throttle() to waitUntilStable()

From the name, I expect "throttle" to mean: only send 1 change per N milliseconds.
But actually the method waits for a "quiet period" of N milliseconds.

I would call it waitUntilStable() or waitUntilStableFor(). Other options are skipUntilStable() or filterUntilStable(), but it doesn't really skip the value, it just holds it until the time has passed.

combineTemplate is broken when only a single stream is combined

Initial value string becomes a single character:

Bacon.combineTemplate({
  lol: new Bacon.Bus().toProperty('wut')
}).onValue(function(e){console.log(e.lol)})
=>  'w'

... and an initial value of false becomes undefined:

Bacon.combineTemplate({
  lol: new Bacon.Bus().toProperty(false)
}).onValue(function(e){console.log(e.lol)})
=> undefined 

When two or more properties are used, it works as expected:

Bacon.combineTemplate({
  lol: new Bacon.Bus().toProperty('lol'),
  wut: new Bacon.Bus().toProperty('wut') 
}).onValue(function(e){console.log(e.lol, e.wut)})
=> 'lol wut'

Customizable build

As pointed out in #69, It would be great to be able to build a custom minified version of Bacon. That would allow us to include more features into the core without bloating the end-user library.

Any ideas how to do this?

Unexpected behaviour when subscribing to properties

It is unclear to me whether the "current value" of a property should be sent to a new onValue subscriber of a property at the instant that they subscribe.

It seems to me that they should receive the "current" value, but maybe there's a reason they shouldn't.

Even so the actual behaviour seems inconsistent. A first subscriber on a stream will not receive the current value, but later subscribers will. Am I missing something or is this a bug?

I have created an example here: http://jsbin.com/itujas/3/edit but the behaviour is below as well.

Basically:

I would expect this to work, and alert 1 but it doesn't do anything until I push another value onto the bus.

var bus = new Bacon.Bus();
var property = bus.toProperty();

bus.push(1);
bus.push(2);

property.onValue(function(value) { alert(value) }); 
   //=> Nothing happens here?

bus.push(3);  //=> Alert "3"

But this works differently

If I register a subscriber, then push a value, then register a second subscriber, the second subscriber receives the latest value on subscribing.

var bus = new Bacon.Bus();
var property = bus.toProperty();

property.onValue(function(value) { alert("First subscriber "+value) });

bus.push(1);   //=> receive alert "First subscriber 1"
bus.push(2);   //=> receive alert "First subscriber 2"

property.onValue(function(value) { alert("Second subscriber "+value) }); 
   //=> receive alert "Second subscriber 2"

This means that if I want to work around this I have to do this:

var bus = new Bacon.Bus();
var property = bus.toProperty();

property.onValue();

bus.push(1);
bus.push(2);

property.onValue(function(value) { alert(value) }); 
   //=> receive alert "2" as I expect.

EventStream.takeUntil spec test incorrect?

According to your documentation for takeUntil, it stops when it sees a Next event, specifically. However, your test for this EventStream requires that either: Bacon.repeatedly immediately sends an Initial event, or that takeUntil should stop upon an Initial event as well.

The way my JBacon library originally implemented everything, it would send the Initial event after the given delay to repeatedly, so the actual values the test should have expected would have been [1, 2, 3, 1] when takeUntil stops upon a Next event. I had to change my code so that the Initial event is sent immediately, and the amount of time before the stopper fires needed to be 5 in order to get the same expected values.

Support multiple-valued side-effect functions

Sometimes it would be convenient to use multi-valued functions in side effects. I'd like to be able to combine a bunch of properties and do something in a function that accepts each property value as a param like

name // Property
age // Property
sex // Property
Bacon.combineAsArray(name, age, sex).onValues(function(name, age, sex) {
  ...
  ...
}) 

Sorry for the stupid example :)

Building and testing

The building/testing system is a bit confusing right now.

  • So far Bacon's been built using cake (the coffeescript compiler) and based on the Cakefile, there's some mangling with uglifyJs and so on.
  • Then there's package.json that defines how to build with npm. It doesn't however invoke cake build. This is how we run tests: npm test
  • Now there's gruntfile.coffee too. It can also be used for compiling and minifying. It isn't in sync with Cakefile, so the minified version won't have the asserts removed (I'm not saying it's necessarily a good idea to discard asserts)

What we should have is a bit less options, I'd say. Should we ditch the Cakefile and go with grunt and npm? Should we make the gruntfile the entry point to all building and testing? What we definitely need is clear instructions for building and testing.

Opinions?

Browser compatibility testing

No problems reported so far (except do/switch that have already been renamed), but just to make sure we're safe, an automated browser test setup would be great.

Build system and C.I.

Bacon.js should have a decent build system (maybe based on grunt?) and a C.I (maybe Travis?). Someone should just do it. Is it you?

Property flattening/switching

Suppose your UI produces a changing list of Things, that themselves are changing. We might model this as a

things :: Property([Property Thing])

in Haskellish, or a "Property whose value is an array of Properties, each of which has a Thing as a value".

I propose we add Property.flatten, which will convert this property into

things' :: Property([Thing])

I've already got the implementation in the Property.flatten branch. I'll merge it into master if anybody finds use for it.

Note that this is fully recursive so it will flatten any nested structures containing mixed static and dynamic data, and will make combineTemplate support the same kind of recursive combination. Actually flatten() is just a combination of flatMapLatest and combineTemplate.

Bus::end shadows EventStream::end

Both Bus and EventStream have methods named end. This breaks bus.decorateWith and property.sampledBy(bus) behavior, as the implementation calls end on the sampled stream.

As a workaround Property::sampledBy could be fixed to always call EventStream::end or filter given stream with true, but I guess either one needs to be renamed to avoid confusion.

combineTemplate breaks on arrays as initial values of a property

Bacon.combineTemplate({
    'first': (new Bacon.Bus()).toProperty(false),
    'second': (new Bacon.Bus()).toProperty([]),
    'third': (new Bacon.Bus()).toProperty(false)
}).map(function(triple) {
    console.log(triple)
    return [triple.first, triple.second, triple.third]
}).onValue(function(e) {console.log('value', e)})
=>
'value [false, false, undefined]'

When the initial value array has something in it the value locations are not messed up, but the value is taken out from the array:

Bacon.combineTemplate({
    'first': (new Bacon.Bus()).toProperty(false),
    'second': (new Bacon.Bus()).toProperty(['initialval']),
    'third': (new Bacon.Bus()).toProperty(false)
}).map(function(triple) {
    console.log(triple)
    return [triple.first, triple.second, triple.third]
}).onValue(function(e) {console.log('value', e)})
=>
'value [false, "initialval", false]'

sample does not work being called before filter

filter(id).sample(50) and sample(50).filter(id) gives different results

        var allKeyUps = $(document).asEventStream("keyup")
        var allKeyDowns = $(document).asEventStream("keydown")

        function always(value) { return function (_) { return value } }
        function keyCodeIs(keyCode) { return function (event) { return event.keyCode == keyCode } }
        function keyDowns(keyCode) { return allKeyDowns.filter(keyCodeIs(keyCode)) }
        function keyUps(keyCode) { return allKeyUps.filter(keyCodeIs(keyCode)) }

        function concat(a1, a2) { return a1.concat(a2) }
        function keyState(keyCode, value) {
            return keyDowns(keyCode).map(always([value])).merge(keyUps(keyCode).map(always([]))).toProperty([0])
        }
        function head(array) { return array[0] }
        var direction = keyState(38, 1)
          .combine(keyState(40, 1), concat)
          .combine(keyState(37, 1), concat)
          .combine(keyState(39, 1), concat)
          .map(head)

        function id(x) { return x }

        var movements = direction.sample(50).filter(id) // !!! filter(id).sample(50) works fine

        movements.log()

JQuery autocomplete does not work: cannot read property 'label' of undefined

bacon.js: 25.11.2012 from repo
JQuery: 1.8.3
JQuery UI: 1.9.2
If I comment out bacon.js autocomplete starts working.

Can be reproduced with:

$(".ajax").hide()
titleField = $("input#title")
title = Bacon.UI.textFieldValue(titleField)
title.log()
titleRequest = title.changes().filter(nonEmpty).throttle(300).map(
function(title) {
return {
url : "thingy/" + title
}
}
)
titleResponse = titleRequest.ajax()
titlesToShow = titleResponse.toProperty(true)
var titles = []
$.each(titlesToShow, function(i, val) {
titles.push(val.title);
})
$("input#title").autocomplete({source:titles})

Add switchCase combinator (rename?)

I need a "switch-case" combinator like this:

var a = Bacon.constant("a")
var b = Bacon.constant("b")
var selector = Bacon.constant("a")

var result = selector.switchCase({"a": a, "b": b})

So the idea is to map, for instance, radio button selections to values from different source Properties. The implementation could be extremely simple:

Bacon.Property.prototype.switchCase = function(cases) {
  var data = Bacon.combineTemplate(cases)
  return this.combine(data, function(key, data) {
    return data[key]
  })
}

Now the question is: what would be the best name? I know there's a switchCase in RxJs but I don't know what it does and don't have docs :)

Rename "switch" -> "flatMapLatest"

Would this be a better name?

This name would clearly link the method to flatMap. Also, it doesn't cause conflict with the switch keyword.

Better suggestions?

Generalize EventStream methods to Property

  • flatMap
  • switch
  • startWith : for injecting an Init value, same as toProperty(initValue)
  • mapEnd
  • scan (in progress, issue 17)

Possibly add

  • toEventStream: makes an event stream that's like p.changes().startWith(p.currentValue)

Semantic versioning

Current release is 0.0.10.

I guess we should be nearer to 1.0.

Should we say we are at 0.9.0?

You tell me.

Version tags for installing with Bower

If I add bacon to my component.json file:

  "dependencies": {
    "bacon": "~0.0.4"
  }

running bower install fails because there are no tags for versions in the repo.

bower cloning git://github.com/raimohanska/bacon.js
bower cached git://github.com/raimohanska/bacon.js
bower fetching bacon
bower error Can not find tag satisfying: bacon#~0.0.4

Bacon.constant possible bug

Bacon.constant emits the value and then an end. This causes issues when you combine with other properties using .and() or .or()

Property#filter should return an EventStream, not a Property

Currently, Property#filter returns a Property. This Property is not well-behaved; observers attached using onValue are not guaranteed to be called:

bus = new Bacon.Bus()
bus.toProperty(0).filter((i) -> i > 0).onValue (v) -> console.log(v)

Further, calling toProperty on this Property is a no-op, so one can't create a new default value.

It seems like this should return an EventStream instead, and be closer to changes().filter(...), since there is no guarantee that any value will ever match the predicate. However, changes still isn't quite appropriate because the initial value is ignored.

Please let me know your thoughts on this issue. I'd be happy to make the changes myself if you agree.

Atomic updates to Properties

Assume you have properties A and B and property C = A + B. Assume that both A and B depend on D, so that when D changes, both A and B will change too.

When D changes d1 -> d2, the value of A a1 -> a2 and B changes b1 -> b2 simultaneously, you'd like C to update atomically so that it would go directly a1+b1 -> a2+b2. Unfortunately, Bacon.js does not recognize simultaneous events/updates and C will have a transitional state like a1+b1 -> a2+b1 -> a2+b2

is() function

Tests whether the current value 'is' the test value. Creates really clean code.

Bacon.Observable.prototype.is = (test) ->
  @map (v) -> v is test

numberStream.is(3.14).toProperty(false)

Change value to value() to allow lazy eval

The value property of the Initlal/Next events should be changed to a function, to allow more flexibility in the implementation.

I don't expect too much problems in application code, as this does not affect the typical APIs. It only affects those who use the value field directly, as in

stream.subscribe(function(event) {
  if (event.hasValue()) {
    doStuffWith(event.value)
  }
})

The main benefits would be on the performance side: huge combineTemplate systems would only be evaluated only when the value is actually accessed, for example when hitting a filter(..) or an onValue(..)

I want to change this before we release 1.0.0, because this is a compatibility breaker for some apps.

Support / discussion forums

So far people have filed issues when they need support, and that's been fine. It might however be smarter to separate support requests from actual bugs / improvements.

General discussion around FRP, Bacon.js and related stuff might also be directed to some other forum than the closed issue #51 :)

Should we use Google Groups for general discussion, and encourage the use of Stack Overflow or Google Groups for support too?

Sporadic test failures

npm test sporadically fails with the following:

Failures:

  1) also accepts a field name instead of combinator function
   Message:
     Expected true to equal false.
   Stacktrace:
     Error: Expected true to equal false.
    at new jasmine.ExpectationResult (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:102:32)
    at null.toEqual (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:1171:29)
    at verifyCleanup (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:924:43)
    at expectPropertyEvents (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:836:14)

and

Failures:

  1) returns events in bursts, passing through errors
   Message:
     Expected [ '<error>', [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ] to equal [ '<error>', [ 1, 2, 3, 4 ], [ 5, 6, 7 ] ].
   Stacktrace:
     Error: Expected [ '<error>', [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ] to equal [ '<error>', [ 1, 2, 3, 4 ], [ 5, 6, 7 ] ].
    at new jasmine.ExpectationResult (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:102:32)
    at null.toEqual (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:1171:29)
    at verifySwitching (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:885:22)

Behavior of ended Streams/Properties

Now if you subscribe to an ended stream, you won't get any callback. Ever. Neither is there any way to query whether your stream has exhausted.

Should we send out an End event to any subscriber that comes in after the stream has ended?

a simple example of bacon.js

hi,

To learn bacon.js I've implemented the "wallet war" of http://alfredodinapoli.wordpress.com/2011/12/24/functional-reactive-programming-kick-starter-guide with bacon.js

http://jsfiddle.net/bika/wGDp8/

but there is one thing I don't like, and would find a better way to handle it

walletChange.onValue(function(ev){
    $fatherWallet.val(ev.target.valueAsNumber+10);
})

eventClick.onValue(function(val){
    $sonWallet.val(parseFloat($sonWallet.val())+val);
    $sonWallet.change()
})

As I trigger walletChange.onValue using $sonWallet.change, the jquery event is passed on, instead of the value of $sonWallet.

I'm not sure whether this can be overcome on the side of jQuery or Bacon, but would like to hear your idea on how to get the value of $sonWallet to be passed into walletChange.onValue.

Otherwise, I'm sending this issue in order to provide a very simple example for bacon.js. Especially having it compared with the corresponding Haskell code, the bacon.js implementation is much easier to grasp (I think).

combine works wrong

var position = movements.scan(startPos, function (pos, move) { return pos + move })

var test = position.combine(position.skip(1), function (r, l) { return { left: l, right: r, toString: function () { return '{left:' + this.left + ', right:' + this.right + '}' } } })

test.log()

expected result is
{left:1,right:2}
{left:2,right:3}
{left:3,right:4}

but the actual result is
{left:1, right:1}
{left:1, right:2}
{left:2, right:2}
{left:2, right:3}
{left:3, right:3}

        var allKeyDowns = $(document).asEventStream("keydown")

        function always(value) { return function (_) { return value } }
        function keyCodeIs(keyCode) { return function (event) { return event.keyCode == keyCode } }
        function keyDowns(keyCode) { return allKeyDowns.filter(keyCodeIs(keyCode)) }

        function concat(a1, a2) { return a1.concat(a2) }
        function keyState(keyCode, value) {
            return keyDowns(keyCode).map(always([value])).toProperty([0])
        }
        function head(array) { return array[0] }
        var direction = keyState(38, 1)
          .combine(keyState(40, 1), concat)
          .combine(keyState(37, 1), concat)
          .combine(keyState(39, 1), concat)
          .map(head)

        function id(x) { return x }

        var movements = direction.filter(id).toEventStream()

        var position = movements.scan(5, function (pos, move) { return pos + move })

        function combine(r, l) { return { left: l, right: r, toString: function () { return '{left:' + this.left + ', right:' + this.right + '}' } } }

        var test = position.combine(position.skip(1), combine)

        test.log()

Performance testing

No problems with performance so far, but it might still be interesting to see how many events a sec you can pump through a bacon system like

src.filter(f1).map(f2).flatMap(f3)

Having that metrics established it would be possible to tweak the fat out of it. If we did this with as many browsers as possible, we'd also know something about browser compatibility. But a command-line node-based metric would be a good start.

in() function

Similar to is, but works with arrays.

Bacon.Observable.prototype.in = (test) ->
  @map (v) -> test.indexOf(v) isnt -1

housingStream.in(['apartment', 'condo']).toProperty(false)

Website (and logo)

I'm planning on setting up a website for bacon.js. So far, I've got some ideas.

This is something I'll need help with. I ain't got mad skillzz with Photoshop, for instance.

I'm thinking something more in the spirit of

francis

than

mrbacon

Enabling/Disabling "example" does not work on buttons

JQuery attr does not work like expected in 'Function Construction rules'

"disableButton.onValue($("#send"), "attr", "disabled") which would call the attr method of the #send element, with "disabled" as the first argument. So if your property has the value true, it would call $("#send").attr("disabled", true)"

Enabling works only by using removeAttr("disabled")

Also quoted in your blog post.

Add windowWithCount

e.g. https://github.com/Reactive-Extensions/rxjs-jquery/blob/master/examples/KonamiCode.html

I might take a stab at this at some point, opening the issue to make sure people think it's a good idea.

my use case:

steps = new Bacon.Bus()
stepStarts = new Bacon.Bus()
stepEnds = new Bacon.Bus()
steps.windowWithCount(2).onValues (oldStep, newStep) ->
  stepEnds.push(oldStep) if oldStep
  stepStarts.push(newStep) if newStep

(then I could throw out this code):

do ->
  oldStep = null
  steps.onValue (newStep) ->
    stepEnds.push(oldStep) if oldStep
    stepStarts.push(newStep) if newStep
    oldStep = newStep

Extension architecture, build scripts, template

Extensions. Libs that add something to Bacon. Something we don't care to include to the core.

For instance, there's Bacon.UI.js. I'd like to have more, like bacon.matchers, bacon.model etc.

Should figure out a smart way to build an extension like this, so that we could run automatic tests, build coffee->minified js, run jslint etc. I'd like to have AMD and Node.js compatibility for all modules too.

I think it would make sense to make a "bacon extension template" that could be used as a starting point for easily making and extension lib with all the aforementioned niceties.

This is not my strong area, so help would be appreciated here :)

support for async callback

Hi,
there is a callback for async callback in map and other functions?

for example

$().ready(function () {
    $(".ss").asEventStream("click").map(function(e,cb) {
      setTimeout(function() {
          cb(5000)
       },1000);
    }).log();
});

function log should write 5000

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.