Code Monkey home page Code Monkey logo

inject'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

inject's Issues

Injecting functions

Hi!

Is there any plans to allow injection of function types? The use case is a pretty standard factory setup; the need to delay the actual creation of a struct until runtime.

An example:

type Create func() string

type Something struct {
  CreateFn Create `inject:""`
}

the solution is to wrap Create into an interface, and have multiple dummy structs implement the interface and inject those instead, but that seems like more boilerplate than should be needed.

Or maybe I'm missing something?

Questions on usage & design

I've been evaluating using this library, and I have a few questions about usage patterns.

I'm fine with a struct declaring certain fields as required (normally done by simply having a constructor), but I'm uncomfortable with a struct knowing the name of the specific instance it should be injected with (even if it uses an interface instead of a specific struct type). It seems that only a higher orchestration layer should know how to tie your classes together. Doesn't this put all names in the same global namespace? Wouldn't you eventually run into conflicts, especially using structs from various sources?

In order to pass struct pointers to Provide, the structs must be publicly accessible, and their injected fields must also be publicly accessible. Was there ever any thought put into accepting a local "context" struct with named fields using interfaces and then passing constructor functions to Provide? This would allow populating private structs that implement public interfaces.

Example:

func NewImplA(b InterfaceB) { return &implA{ b: b } }
func NewImplB() { return &implB{} }

type Context struct {
    A InterfaceA 
    B InterfaceB 
}

func main() {
    var context Context
    context.B = NewImplB()
    inject.Provide(&context, context.B, NewImplB)
    inject.Provide(&context, context.A, NewImplA)
}

If the structs needing injection all must be publicly accessible, and each struct also needs an interface to allow for mocking/faking for testing, what pattern do you use for naming your structs/interfaces when they only have one implementation?

Populate/Provide returns err

Hello,

I've been using enjoying using inject in my projects. Thank you for open sourcing this library!

I've found one inconsistency that doesn't seem 'go-like' is that object.Populate, graph.Provide, and graph.Populate all return err without panicking. I feel that all of the errors that are passed back are not recoverable errors and require the developer to change their usage of library. Failing to check for the error leaves the graph in a bad state, but checking for errors is also somewhat onerous.

Rather than change the behavior, and break backwards compatibility, I would suggest adding a MustProvide and MustPopulate that would panic immediately upon receiving an error. I would be happy to submit a patch if you believe it's a good idea, as I've wrapped the functionality already.

Cheers,
Kevin

Injection Scope

Hi All,

This is more of a discussion than an issue, and if there's a better forum for such conversations I apologize for not using it. I did not see on mentioned in the article.

What I'd really like to do with inject is to fork and enhance it to have injection scopes, much like Spring. Whether it's request based, thread based, or a custom scope, it all comes down to enabling some form of consistent way of sharing instances of objects with one another in some isolated boundary while there may be more of those isolated boundaries with different instances of the same types.

Ultimately I think this is made difficult to impossible? by golang's lack of threads. Since goroutines are multiplexed onto multiple OS threads, we can never truly know where code is executing, so there's no real good way to use something like a ThreadLocal to maintain any consistent ID.

The best solution of which I'm able to conceive is having multiple object graphs with a single graph at the root that provides true singletons to the other, scoped graphs. Instances of the scoped graphs would have to be passed around to any and all type instances involved in that scope in case they needed to contribute or request some type of object from the graph. At the very least there would have to be a scope entry point where a new, scoped graph is initialized using a combination of objects provided from the shared graph and new ones created from the scoped graph.

I'd love to hear your thoughts on this. The use case is where I'm building a server that can load multiple module instances. These instances can be different module types or the same module type, all configured as the user sees fit per the initialization routine. Because the modules obviously share some common dependencies (especially the instances of the same type), I'd like to make it as painless as possible to create scopes per module instance, scopes that include the modules' dependencies, be they scoped as singletons or to the module instance.

Thank you for your time!

possible to allow binding of empty structs?

I have a library https://github.com/jmhodges/clock, that provides an interface Clock that is satisfied by an empty struct which is returned by New.

I've been working in a codebase that uses inject. We tried adding clock.Clock at an injection point, and only ran into trouble when going to a production-like deploy because inject rejects structs without a pointer.

Is there anyway that restriction could be loosened for empty structs? There's no danger in state getting lost by copy.

Perhaps, there was another reason for that restriction, though. Would love to hear it!

How to achieve substitution in tests with mocks if interface references cannot be injected?

Like so many others before, I'd like to leverage the benefits of DI by using the same references on a struct I'm testing for manually set mock/stub structs in addition to having Inject populate them at normal runtime.

However, in Golang, there's no Liskov-style substitution unless you're using interfaces. The Inject doc mentions that "supports injection for interface types as long as they’re unambiguous", but I'm not sure what is meant there or if it's even relevant to this problem.

I'd rather avoid having to manually create all such substitutable structs, because that means I'd have to create all such things at the top level, partially negating the value of using Inject (having a highly-polluted main()).

Perhaps an extra parameter to the inject tag to indicate which object should be constructed to satisfy the interface requirement by default?

Activity

Would it be safe to assume that this project is dead from FB point of view?

Simplify the population of an app container

Hello, thanks a lot for this lib, I use it in a lot of projects.

Something that I find myself repeatedly doing is:

func main() {
    a := &A{}
    b := &B{}
    c := &C{}

    if err := inject.Populate(a, b, c); err != nil {
        // ...
    }
}

As the app grows, the number of objects grows as well and the above code ends up being a lot of boilerplate.

I tried to mitigate this by using a function like this one :

func PopulateContainer(container interface{}) error {
	s := reflect.ValueOf(container).Elem()

	if s.CanSet() {
		for i := 0; i < s.NumField(); i++ {
			f := s.Field(i)
			if f.Kind() == reflect.Ptr && f.IsNil() {
				v := reflect.New(f.Type().Elem())
				f.Set(v)
			}
		}
	}

	var injectablesList []interface{}
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if f.CanInterface() {
			injectablesList = append(injectablesList, f.Interface())
		}
	}

	return inject.Populate(injectablesList...)
}

The user code then looks like:

type AppContainer struct {
    *A
    *B
    *C
}

func main() {
    c := AppContainer{}

    if err := PopulateContainer(&c); err != nil {
        // ...
    }
}

What do you think about it? Maybe you used a different approach?
What is your feeling about including a similar helper function directly in the lib?

What's with the license?

Any chance this can be released under something like MIT or Apache or something without that funky patent clause in it?

Regardless of arguments for/against that clause, are you sure that company policy requires it to be used in this case? It's a pretty small project and not something of core importance to FB or likely to have any monetary value. That license seems a bit overkill, if not generally, at least in this case for this project.

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.